package ui import ( "errors" "fmt" "go_dreamfactory/cmd/v2/lib/common" "go_dreamfactory/cmd/v2/model" "go_dreamfactory/cmd/v2/service" "go_dreamfactory/cmd/v2/service/observer" "go_dreamfactory/utils" "io/ioutil" "os/exec" "path/filepath" "runtime" "sort" "strings" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "github.com/sirupsen/logrus" ) type appGen struct { appAdapter obs observer.Observer goList *fileList jsonList *fileList } func (this *appGen) LazyInit(obs observer.Observer) error { this.obs = obs this.goList = NewFileList() this.jsonList = NewFileList() this.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_GEN, theme.ContentCopyIcon(), nil) // load gt := service.GetDbService().GetLubanConf(common.BUCKET_LUBANCONF) logrus.Debugf("%v", gt) content := container.NewMax() content.Objects = []fyne.CanvasObject{} serverAddr := widget.NewEntry() serverAddr.PlaceHolder = "服务器地址 例如: 10.0.1.11" projectDir := widget.NewEntry() projectDir.PlaceHolder = `项目目录 例如: E:\projects\workspace\go_dreamfactory\` workDir := widget.NewEntry() workDir.PlaceHolder = `LuBan目录 例如: E:\svn\dreamworks\client\dreamworks\ExcelFile\` // client client := widget.NewEntry() client.Text = `Luban.Client\Luban.Client.exe` client.PlaceHolder = `配置Luban Client.exe路径` //define define := widget.NewEntry() define.PlaceHolder = "定义文件" define.Text = `Defines\\__root__.xml` // output outputCodeDir := widget.NewEntry() outputCodeDir.Text = `sys\configure\structs` outputJsonDir := widget.NewEntry() outputJsonDir.Text = `bin\json` //input inputDir := widget.NewEntry() inputDir.Text = "Datas" tmpDir := widget.NewEntry() tmpDir.Text = filepath.Join(`c:\tmp\`) tmpDir.PlaceHolder = "临时目录,不要和工作目录和项目目录重复" //genType var genTypeText string genType := widget.NewSelect([]string{"go", "json", "all"}, func(s string) { genTypeText = s }) genType.PlaceHolder = "生成类型" if gt != nil { serverAddr.Text = gt.ServerAddr projectDir.Text = gt.ProjectDir workDir.Text = gt.WorkDir client.Text = gt.Client genType.Selected = gt.GenType genTypeText = gt.GenType tmpDir.Text = gt.TmpDir } // 打开目录 openFolder := func(entry *widget.Entry) { dConf := dialog.NewFolderOpen(func(lu fyne.ListableURI, err error) { if lu == nil { return } entry.Text = lu.Path() entry.Refresh() }, toolWin.w) luri, _ := storage.ListerForURI(storage.NewFileURI(".")) dConf.SetLocation(luri) dConf.SetConfirmText("打开") dConf.SetDismissText("取消") dConf.Resize(fyne.NewSize(750, 500)) dConf.Show() } form := widget.NewForm( widget.NewFormItem("服务地址", serverAddr), widget.NewFormItem("项目目录", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FolderIcon(), func() { openFolder(projectDir) }), projectDir)), widget.NewFormItem("工作目录", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FolderIcon(), func() { openFolder(workDir) }), workDir)), widget.NewFormItem("LuBan Cli", client), widget.NewFormItem("输入目录", inputDir), widget.NewFormItem("输出Code目录", outputCodeDir), widget.NewFormItem("输出JSON目录", outputJsonDir), widget.NewFormItem("临时目录", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FolderIcon(), func() { openFolder(tmpDir) }), tmpDir)), widget.NewFormItem("生成类型", genType), ) getType := func() string { if genTypeText == "" { return "" } else { if genTypeText == "go" { return "code_go_json" } else if genTypeText == "json" { return "data_json" } else if genTypeText == "all" { return "code_go_json,data_json" } } return "" } saveBtn := widget.NewButtonWithIcon("保存配置", theme.DocumentSaveIcon(), func() { if err := service.GetDbService().SaveLubanConf(&model.GenTool{ ServerAddr: serverAddr.Text, ProjectDir: projectDir.Text, Client: client.Text, WorkDir: workDir.Text, InputDir: inputDir.Text, OutputCodeDir: outputCodeDir.Text, OutputJsonDir: outputJsonDir.Text, GenType: genTypeText, TmpDir: tmpDir.Text, }); err != nil { logrus.WithField("err", err).Debug("保存配置") } logrus.Debug("save luban conf") }) //go this.goList.titleLabel = widget.NewLabel("Go文件") this.goList.titleLabel.Hide() // 复选列表 this.goList.itemList = this.goList.createList() // 覆盖 -go go_allSelBtn := &widget.Button{Icon: theme.CheckButtonIcon()} go_allCancelBtn := &widget.Button{Icon: theme.CheckButtonCheckedIcon()} go_overrideBtn := &widget.Button{Text: "覆盖", Icon: theme.ConfirmIcon()} go_overrideBtn.Hide() go_allSelBtn.Hide() // 覆盖 go_overrideBtn.OnTapped = func() { go_overrideBtn.Disable() defer func() { go_overrideBtn.Enable() this.goList.itemList.Refresh() }() for _, v := range this.goList.selItemIds { // logrus.WithField("path1", filepath.Join(tmpDir.Text, "go", v)).Debug("copy go") // logrus.WithField("path2", filepath.Join(projectDir.Text, outputCodeDir.Text, v)).Debug("copy go") _, err := common.Copy(filepath.Join(tmpDir.Text, "go", v), filepath.Join(projectDir.Text, outputCodeDir.Text, v)) if err != nil { logrus.Error(err) return } this.goList.deleteItem(v) } this.goList.changeFileCount() } //取消checked go_allCancelBtn.OnTapped = func() { defer func() { go_allCancelBtn.Hide() go_allSelBtn.Show() }() this.goList.selItemIds = []string{} for i, v := range this.goList.cachedList.Items { this.goList.cachedList.Items[i].Checked = false this.goList.itemList.UpdateItem(i, widget.NewCheck(v.Text, nil)) } this.goList.changeFileCount() // this.goList.titleLabel.SetText(fmt.Sprintf("(%d/%d)", len(this.goList.selItemIds), this.goList.fileTotal)) this.goList.itemList.Refresh() } //选择所有 go_allSelBtn.OnTapped = func() { defer func() { go_allCancelBtn.Show() go_allSelBtn.Hide() }() for i, v := range this.goList.cachedList.Items { this.goList.cachedList.Items[i].Checked = true this.goList.selItemIds = append(this.goList.selItemIds, v.Text) this.goList.itemList.UpdateItem(i, widget.NewCheck(v.Text, nil)) } this.goList.titleLabel.SetText(fmt.Sprintf("(%d/%d)", len(this.goList.selItemIds), this.goList.fileTotal)) this.goList.itemList.Refresh() } // json this.jsonList.titleLabel = widget.NewLabel("Json文件") this.jsonList.titleLabel.Hide() // 复选列表 this.jsonList.itemList = this.jsonList.createList() // 覆盖 -go json_allSelBtn := &widget.Button{Icon: theme.CheckButtonIcon()} json_allCancelBtn := &widget.Button{Icon: theme.CheckButtonCheckedIcon()} json_overrideBtn := &widget.Button{Text: "覆盖", Icon: theme.ConfirmIcon()} json_overrideBtn.Hide() json_allSelBtn.Hide() json_overrideBtn.OnTapped = func() { json_overrideBtn.Disable() defer func() { json_overrideBtn.Enable() this.jsonList.itemList.Refresh() }() for _, v := range this.jsonList.selItemIds { // logrus.WithField("path1", filepath.Join(tmpDir.Text, "json", v)).Debug("copy json") // logrus.WithField("path2", filepath.Join(projectDir.Text, outputJsonDir.Text, v)).Debug("copy json") _, err := common.Copy(filepath.Join(tmpDir.Text, "json", v), filepath.Join(projectDir.Text, outputJsonDir.Text, v)) if err != nil { logrus.Error(err) return } this.jsonList.deleteItem(v) } this.jsonList.changeFileCount() } //取消checked json_allCancelBtn.OnTapped = func() { defer func() { json_allCancelBtn.Hide() json_allSelBtn.Show() }() list := this.jsonList list.selItemIds = []string{} for i, v := range list.cachedList.Items { list.cachedList.Items[i].Checked = false list.itemList.UpdateItem(i, widget.NewCheck(v.Text, nil)) } this.jsonList.changeFileCount() // list.titleLabel.SetText(fmt.Sprintf("(%d/%d)", len(list.selItemIds), list.fileTotal)) list.itemList.Refresh() } //选择所有 json_allSelBtn.OnTapped = func() { defer func() { json_allCancelBtn.Show() json_allSelBtn.Hide() }() list := this.jsonList for i, v := range list.cachedList.Items { list.cachedList.Items[i].Checked = true list.selItemIds = append(list.selItemIds, v.Text) list.itemList.UpdateItem(i, widget.NewCheck(v.Text, nil)) } list.changeFileCount() list.itemList.Refresh() } genBtn := &widget.Button{Text: "生成", Icon: theme.ConfirmIcon()} genBtn.OnTapped = func() { genBtn.Disable() defer func() { genBtn.Enable() go_allCancelBtn.Show() go_allSelBtn.Hide() json_allCancelBtn.Show() json_allSelBtn.Hide() }() if runtime.GOOS != "windows" { dialog.ShowError(errors.New("no support "+runtime.GOOS), toolWin.w) return } if genTypeText == "" { dialog.ShowError(errors.New("类型未选择"), toolWin.w) return } commandStr := `%s -h %s -j cfg -- -d %s --input_data_dir %s --output_code_dir %s --output_data_dir %s --gen_types %s --go:bright_module_name bright -s server` arg := fmt.Sprintf(commandStr, filepath.Join(workDir.Text, client.Text), serverAddr.Text, filepath.Join(workDir.Text, define.Text), filepath.Join(workDir.Text, inputDir.Text), filepath.Join(tmpDir.Text, "go"), filepath.Join(tmpDir.Text, "json"), getType(), ) logrus.Debug(arg) c := exec.Command("cmd.exe", "/c", arg) if err := c.Run(); err != nil { dialog.ShowError(err, toolWin.w) return } changeGo := func() { this.goList.changeItem(filepath.Join(tmpDir.Text, "go"), filepath.Join(projectDir.Text, outputCodeDir.Text)) this.goList.titleLabel.SetText(fmt.Sprintf("(%d/%d个)", len(this.goList.selItemIds), this.goList.fileTotal)) go_overrideBtn.Show() this.goList.titleLabel.Show() } changeJson := func() { this.jsonList.changeItem(filepath.Join(tmpDir.Text, "json"), filepath.Join(projectDir.Text, outputJsonDir.Text)) this.jsonList.titleLabel.SetText(fmt.Sprintf("(%d/%d)", len(this.jsonList.selItemIds), this.jsonList.fileTotal)) json_overrideBtn.Show() this.jsonList.titleLabel.Show() } // 更新列表 if genTypeText == "go" { changeGo() } else if genTypeText == "json" { changeJson() } else if genTypeText == "all" { changeGo() changeJson() } } //使用说明 desBtn := widget.NewButtonWithIcon("", theme.QuestionIcon(), func() { quesWin := fyne.CurrentApp().NewWindow("使用说明") quesWin.SetContent(widget.NewRichTextFromMarkdown( ` 1. SVN更新excel文件 2. 配置Luban(已做可忽略) 3. 选择**生成类型**,单击生成 4. 选择要覆盖的文件 `)) quesWin.Resize(fyne.NewSize(350, 200)) quesWin.SetFixedSize(true) quesWin.CenterOnScreen() quesWin.Show() }) // layout left := container.NewVBox(form, container.NewHBox(&layout.Spacer{}, desBtn, saveBtn, genBtn)) right := container.NewGridWithColumns(2, container.NewBorder( container.NewHBox(go_allSelBtn, go_allCancelBtn, go_overrideBtn, widget.NewLabel("Go文件"), this.goList.titleLabel), nil, nil, nil, this.goList.itemList), container.NewBorder( container.NewHBox(json_allSelBtn, json_allCancelBtn, json_overrideBtn, widget.NewLabel("Json文件"), this.jsonList.titleLabel), nil, nil, nil, this.jsonList.itemList)) content.Objects = append(content.Objects, container.NewGridWithColumns(2, left, right)) this.tabItem.Content = content return nil } type fileList struct { selItemIds []string //选择的ID fileTotal int //文件总数 titleLabel *widget.Label cachedList List itemList *widget.List } func NewFileList() *fileList { return &fileList{ titleLabel: &widget.Label{}, cachedList: NewList(""), } } func (f *fileList) createList() *widget.List { f.itemList = widget.NewList( func() int { return len(f.cachedList.Items) }, func() fyne.CanvasObject { return widget.NewCheck("Template", func(bool) {}) }, func(id widget.ListItemID, item fyne.CanvasObject) { c, _ := item.(*widget.Check) c.Text = f.cachedList.Items[id].Text c.Checked = f.cachedList.Items[id].Checked c.OnChanged = func(b bool) { if b { f.selItemIds = append(f.selItemIds, c.Text) } else { f.selItemIds = utils.DeleteString(f.selItemIds, c.Text) } f.titleLabel.SetText(fmt.Sprintf("(%d/%d)", len(f.selItemIds), f.fileTotal)) f.cachedList.Items[id].Checked = b // sort.Sort(f.cachedList) f.itemList.Refresh() } c.Refresh() }, ) return f.itemList } func (f *fileList) addItem(val string) { val = strings.TrimSpace(val) if len(val) == 0 { return } newItem := Item{ Text: val, Quantity: 1, Checked: true, //默认选中 } f.cachedList.Items = append(f.cachedList.Items, newItem) sort.Sort(f.cachedList) f.itemList.Refresh() } func (f *fileList) deleteItem(name string) { for i, v := range f.cachedList.Items { if v.Text == name { f.selItemIds = utils.DeleteString(f.selItemIds, v.Text) f.cachedList.Items = append(f.cachedList.Items[:i], f.cachedList.Items[i+1:]...) if f.fileTotal > 0 { f.fileTotal-- } } } } // 改变列表项目 func (f *fileList) changeItem(tmpDir, projectDir string) { f.fileTotal = 0 f.selItemIds = []string{} f.cachedList = NewList("") tmpFiles, err := ioutil.ReadDir(tmpDir) if err != nil { logrus.Error(err) return } defer func() { if len(tmpFiles) == 0 || len(f.cachedList.Items) == 0 { showTip("没有任何变更的文件,请确定SVN拉取最新文件") } }() projectFiles, err := ioutil.ReadDir(projectDir) if err != nil { logrus.Error(err) return } pfMap := make(map[string]int64) for _, v := range projectFiles { if !v.IsDir() { pfMap[v.Name()] = v.ModTime().Unix() } } for _, file := range tmpFiles { if !file.IsDir() { if pfTime, ok := pfMap[file.Name()]; ok { if file.ModTime().Unix() <= pfTime { continue } } f.addItem(file.Name()) f.selItemIds = append(f.selItemIds, file.Name()) f.fileTotal++ logrus.Debugf("%v", file.Name()) } } } // 刷新文件数 func (f *fileList) changeFileCount() { f.titleLabel.SetText(fmt.Sprintf("(%d/%d)", len(f.selItemIds), f.fileTotal)) } func (a *appGen) GetAppName() string { return common.TOOLBAR_GEN }