From b3cf948fd2d6fa4685ec289f364475843e4d9386 Mon Sep 17 00:00:00 2001 From: shine <1042864399@qq.com> Date: Tue, 15 Oct 2024 21:13:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E8=81=8A=E5=A4=A9=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=20=E5=88=9D=E6=AD=A5=E6=9E=84=E5=BB=BA=E5=8D=81?= =?UTF-8?q?=E5=AD=90=E6=A3=8B=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf.ini | 7 +++ global/data.go | 1 + global/data_test.go | 28 ++++++++-- models/message.go | 47 ++++++++++++++-- repo/chatMessage.go | 21 ++++++++ repo/user.go | 2 +- repo/userFollow.go | 4 +- service/baseCardService.go | 28 ++++++++++ service/client.go | 2 +- service/server.go | 13 ++--- views/chatView.go | 97 ++++++++++++++++++++------------- views/followUsers.go | 2 + views/gamesViews.go | 106 +++++++++++++++++++++++++++++++++++++ views/otherUsers.go | 28 +--------- views/userView.go | 1 + 15 files changed, 303 insertions(+), 84 deletions(-) create mode 100644 conf.ini create mode 100644 repo/chatMessage.go create mode 100644 views/gamesViews.go diff --git a/conf.ini b/conf.ini new file mode 100644 index 0000000..1507d20 --- /dev/null +++ b/conf.ini @@ -0,0 +1,7 @@ +db_path=data/data.db +card_dir=data +card_info=package.json +avatar=data/avatar +zeroconf_key=work_cations_service +zeroconf_port=16800 +server_addr=:16805 \ No newline at end of file diff --git a/global/data.go b/global/data.go index 176108e..b9fc2aa 100644 --- a/global/data.go +++ b/global/data.go @@ -22,6 +22,7 @@ func InitDB() { &models.Users{}, &models.UserFollows{}, &models.BaseCard{}, + &models.ChatMessage{}, ) if err != nil { panic(err) diff --git a/global/data_test.go b/global/data_test.go index 89233ac..b493d93 100644 --- a/global/data_test.go +++ b/global/data_test.go @@ -41,14 +41,14 @@ func TestP2(t *testing.T) { ) f := func(tx *gorm.DB) *gorm.DB { - // Find SELECT `id`,`value` FROM `test_models` WHERE id = 1 AND `test_models`.`deleted_at` IS NULL ORDER BY ID desc - // First SELECT `id`,`value` FROM `test_models` WHERE id = 1 AND `test_models`.`deleted_at` IS NULL ORDER BY ID desc,`test_models`.`id` LIMIT 1 + // Find SELECT `id`,`value` FROM `test_models` WHERE id = 1 AND `test_models`.`deleted_at` IS NULL ORDER BY UserID desc + // First SELECT `id`,`value` FROM `test_models` WHERE id = 1 AND `test_models`.`deleted_at` IS NULL ORDER BY UserID desc,`test_models`.`id` LIMIT 1 // row value misused 滥用 return tx. Where("id in ?", id). //Or("id = ? ", id+1). Select("value"). - Order("ID desc").Find(&row) + Order("UserID desc").Find(&row) } testSql(db, f) @@ -65,7 +65,7 @@ func TestP3(t *testing.T) { f := func(tx *gorm.DB) *gorm.DB { // Update `test_models` SET `value`="[1 2]",`updated_at`="2024-10-05 13:21:47.253" WHERE id in (1,2) AND `test_models`.`deleted_at` IS NULL 返回个数:2 err: - // Save SELECT `id`,`value` FROM `test_models` WHERE id = 1 AND `test_models`.`deleted_at` IS NULL ORDER BY ID desc,`test_models`.`id` LIMIT 1 + // Save SELECT `id`,`value` FROM `test_models` WHERE id = 1 AND `test_models`.`deleted_at` IS NULL ORDER BY UserID desc,`test_models`.`id` LIMIT 1 // row value misused 滥用 return tx.Model(&TestModel{}). Where("id in ?", 5). @@ -75,7 +75,7 @@ func TestP3(t *testing.T) { //Update("value", []byte(fmt.Sprintf("%d", id))) //Or("id = ? ", id+1). //Select("value"). - //Order("ID desc").Find(&row) + //Order("UserID desc").Find(&row) } testSql(db, f) @@ -177,3 +177,21 @@ func convertToUTF8(input string) (string, error) { return utf8Str, nil } + +type TestMode2 struct { + Name string `json:"name"` + Level int +} +type TestMode3 struct { + T TestMode2 + Name string `json:"name1"` +} + +func TestP11(t *testing.T) { + var t1 = TestMode3{ + T: TestMode2{Name: "测试1", Level: 1}, + Name: "测试2", + } + fmt.Println(t1) + +} diff --git a/models/message.go b/models/message.go index 72588b4..98b69c6 100644 --- a/models/message.go +++ b/models/message.go @@ -1,14 +1,53 @@ package models -import "time" +import ( + "time" +) type ChatMessage struct { - User Users - Time time.Time - Text string + UserID string + UserName string + CreateTx time.Time + Type string + Text string } + +const ( + ChatTypeText = "TEXT" // 对话 + ChatTypeCard = "CARD" // 工具卡片分享 +) + +func NewTextChatMsg(user *Users, text string) *ChatMessage { + return &ChatMessage{ + UserID: user.ID, + UserName: user.Name, + CreateTx: time.Now(), + Type: ChatTypeText, + Text: text, + } +} + type Message struct { Cmd string User UserFollows ChatMessage ChatMessage } + +// +//// Value 接口,Value 返回 json value any -> string +//func (j *Users) Value() (driver.Value, error) { +// return json.Marshal(j) +//} +// +//// Scan 接口,Scan 将 value 扫描至 Jsonb +//func (j *Users) Scan(value interface{}) error { +// bytes, ok := value.([]byte) +// if !ok { +// return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value)) +// } +// err := json.Unmarshal(bytes, j) +// if err != nil { +// return err +// } +// return nil +//} diff --git a/repo/chatMessage.go b/repo/chatMessage.go new file mode 100644 index 0000000..53f64b0 --- /dev/null +++ b/repo/chatMessage.go @@ -0,0 +1,21 @@ +package repo + +import ( + "gorm.io/gorm" + "work_cation/models" +) + +type chatMessageRepo struct{} + +var ChatMsg = &chatMessageRepo{} + +func (*chatMessageRepo) GetUserMsgs(db *gorm.DB, uuid string, limit int) []models.ChatMessage { + var msgs []models.ChatMessage + // ASC:升序(默认),DESC:降序。 + db.Order("create_tx ASC").Limit(limit).Where("user_id = ?", uuid).Find(&msgs) + return msgs +} + +func (*chatMessageRepo) Create(db *gorm.DB, msg *models.ChatMessage) error { + return db.Create(msg).Error +} diff --git a/repo/user.go b/repo/user.go index 716da3e..a692b59 100644 --- a/repo/user.go +++ b/repo/user.go @@ -45,5 +45,5 @@ func (u *userRepo) GetUserInfo(db *gorm.DB) *models.Users { func (u *userRepo) Update(db *gorm.DB, newUser *models.Users) error { u.isNew = false - return db.Model(&models.Users{}).Where("ID = ?", newUser.ID).Updates(newUser).Error + return db.Model(&models.Users{}).Where("UserID = ?", newUser.ID).Updates(newUser).Error } diff --git a/repo/userFollow.go b/repo/userFollow.go index 3eea325..95b60d4 100644 --- a/repo/userFollow.go +++ b/repo/userFollow.go @@ -10,7 +10,7 @@ type userFollowRepo struct{} var UserFollow = &userFollowRepo{} func (u *userFollowRepo) Follow(db *gorm.DB, user *models.UserFollows) error { - return db.Create(user).Error + return db.Model(&models.UserFollows{}).Create(user).Error } func (u *userFollowRepo) GetUser(db *gorm.DB, uuid string) *models.UserFollows { @@ -25,7 +25,7 @@ func (u *userFollowRepo) GetUser(db *gorm.DB, uuid string) *models.UserFollows { return &user } func (u *userFollowRepo) UnFollow(db *gorm.DB, user *models.UserFollows) error { - return db.Where("id = ?", user.ID).Delete(user).Error + return db.Model(&models.UserFollows{}).Where("id = ?", user.ID).Delete(user).Error } func (u *userFollowRepo) All(db *gorm.DB) ([]models.UserFollows, error) { var users []models.UserFollows diff --git a/service/baseCardService.go b/service/baseCardService.go index 5fae698..247fd45 100644 --- a/service/baseCardService.go +++ b/service/baseCardService.go @@ -1,10 +1,15 @@ package service import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/dialog" + "fyne.io/fyne/v2/widget" "gorm.io/gorm" "os" "path/filepath" "work_cation/cfg" + "work_cation/global" "work_cation/models" "work_cation/repo" ) @@ -30,3 +35,26 @@ func (*BaseCardService) Delete(db *gorm.DB, deleteCard models.BaseCard) error { err = db.Model(&models.BaseCard{}).Where("uuid = ?", deleteCard.UUID).Delete(&deleteCard).Error return err } + +func (*BaseCardService) DownloadCard(w fyne.Window, baseCardCopy models.BaseCard, online *models.Online) { + progress := binding.NewFloat() + progress.Set(0) + progressBar := widget.NewProgressBarWithData(progress) + progressBar.Max = 120 + smaillWin := dialog.NewCustom("下载中", "关闭", progressBar, w) + smaillWin.Show() + err := Client.Download(online, baseCardCopy.UUID, progress) + if err != nil { + smaillWin.SetDismissText("失败") + return + } + // 修改数据 + progress.Set(110) + err = repo.BaseCard.CreateOrSave(global.DB, &baseCardCopy) + if err != nil { + smaillWin.SetDismissText("失败") + return + } + progress.Set(120) + smaillWin.SetDismissText("完成 请去[我的]查看") +} diff --git a/service/client.go b/service/client.go index 5a6d12d..0b0b35b 100644 --- a/service/client.go +++ b/service/client.go @@ -127,7 +127,7 @@ func (c *ClientService) Chat(online *models.Online, text string) (string, error) return "", err } res.Header.Set("Content-Type", "application/json") - res.Header.Set("User-ID", user.ID) + res.Header.Set("User-UserID", user.ID) resp, err := http.DefaultClient.Do(res) if err != nil { return "", err diff --git a/service/server.go b/service/server.go index 62f98b5..994f71b 100644 --- a/service/server.go +++ b/service/server.go @@ -10,7 +10,6 @@ import ( "net/http" "os" "path/filepath" - "time" "work_cation/cfg" "work_cation/global" "work_cation/models" @@ -86,7 +85,7 @@ func (s *serverService) StartListenServer() error { }) router.POST("/chat", func(c *gin.Context) { - uuid := c.GetHeader("User-ID") + uuid := c.GetHeader("User-UserID") user := repo.UserFollow.GetUser(global.DB, uuid) if user.Ip != c.ClientIP() { c.JSON(200, gin.H{"message": "对方未关注你"}) @@ -98,13 +97,9 @@ func (s *serverService) StartListenServer() error { return } message := &models.Message{ - Cmd: "chat", - User: *user, - ChatMessage: models.ChatMessage{ - User: user.Users, - Time: time.Now(), - Text: msg["text"].(string), - }, + Cmd: "chat", + User: *user, + ChatMessage: *models.NewTextChatMsg(&user.Users, msg["text"].(string)), } global.Send.SendChan <- message c.JSON(200, gin.H{"message": "ok"}) diff --git a/views/chatView.go b/views/chatView.go index df6cd4b..b6b3156 100644 --- a/views/chatView.go +++ b/views/chatView.go @@ -5,6 +5,7 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/dialog" + "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "time" "work_cation/cfg" @@ -23,6 +24,7 @@ type ChatUserInfo struct { messages []models.ChatMessage shows *fyne.Container scroll *container.Scroll + w fyne.Window } var chat = &ChatView{usersChat: make(map[string]*ChatUserInfo)} @@ -35,13 +37,16 @@ func ListenChat() { if userInfo == nil { userInfo = &ChatUserInfo{} chat.usersChat[message.User.ID] = userInfo + userInfo.messages = repo.ChatMsg.GetUserMsgs(global.DB, message.User.ID, -1) } userInfo.messages = append(userInfo.messages, message.ChatMessage) + _ = repo.ChatMsg.Create(global.DB, &message.ChatMessage) userInfo.Users = message.User.Users if userInfo.shows == nil { OpenChat(message.User.Users) } else { userInfo.shows.Add(itemMessage(message.ChatMessage)) + userInfo.w.RequestFocus() userInfo.scroll.ScrollToBottom() } } @@ -53,11 +58,12 @@ func OpenChat(user models.Users) { if userInfo == nil { userInfo = &ChatUserInfo{} chat.usersChat[user.ID] = userInfo + userInfo.messages = repo.ChatMsg.GetUserMsgs(global.DB, user.ID, -1) } if userInfo.shows == nil { - w := fyne.CurrentApp().NewWindow(user.Name) + w := fyne.CurrentApp().NewWindow(fmt.Sprintf("%s %s", user.Name, user.Ip)) w.CenterOnScreen() - w.Resize(fyne.NewSize(500, 300)) + w.Resize(fyne.NewSize(500, 420)) list := container.NewVBox() for _, item := range userInfo.messages { list.Add(itemMessage(item)) @@ -67,59 +73,78 @@ func OpenChat(user models.Users) { scroll.ScrollToBottom() // 发送表单 en := widget.NewEntry() - formBase := &widget.Form{ - SubmitText: "发送", - OnSubmit: func() { - if en.Text == "" { - return - } - online := service.Zeroconf.GetOnline(user.ID) - if online == nil { - online = &models.Online{ID: user.ID, Ip: user.Ip, Port: cfg.T.ServerAddr} - } - msg, err := service.Client.Chat(online, en.Text) - if err != nil || msg != "ok" { - dialog.ShowInformation("发送失败", err.Error(), w) - return - } - chatItem := models.ChatMessage{ - User: *repo.User.GetUserInfo(global.DB), - Time: time.Now(), - Text: en.Text, - } - userInfo.messages = append(userInfo.messages, chatItem) - list.Add(itemMessage(chatItem)) - en.SetText("") - scroll.ScrollToBottom() - }} + submit := func() { + if en.Text == "" { + return + } + online := service.Zeroconf.GetOnline(user.ID) + if online == nil { + online = &models.Online{ID: user.ID, Ip: user.Ip, Port: cfg.T.ServerAddr} + } + msg, err := service.Client.Chat(online, en.Text) + if err != nil || msg != "ok" { + dialog.ShowInformation("发送失败", err.Error(), w) + return + } + my := repo.User.GetUserInfo(global.DB) + chatItem := models.NewTextChatMsg(my, en.Text) + userInfo.messages = append(userInfo.messages, *chatItem) + _ = repo.ChatMsg.Create(global.DB, chatItem) + list.Add(itemMessage(*chatItem)) + en.SetText("") + scroll.ScrollToBottom() + } + + // 分享 + toolBar := widget.NewToolbar( + widget.NewToolbarAction(theme.ContentAddIcon(), func() { + dialog.ShowInformation("未开发", "分享脚本功能 尽请期待", w) + }), + widget.NewToolbarAction(theme.CancelIcon(), func() { w.Close() }), + ) + button := widget.NewButton("", submit) + button.SetIcon(theme.ConfirmIcon()) + en.OnSubmitted = func(_ string) { submit() } + w.SetContent(container.NewBorder(nil, + container.NewBorder(nil, toolBar, nil, button, en), + nil, nil, scroll)) - formBase.AppendItem(&widget.FormItem{Text: "", Widget: en}) - w.SetContent(container.NewBorder(nil, formBase, nil, nil, scroll)) userInfo.shows = list + userInfo.w = w + w.SetOnClosed(func() { userInfo.shows = nil userInfo.scroll = nil + userInfo.w = nil }) w.Show() } + userInfo.w.RequestFocus() userInfo.scroll.ScrollToBottom() } func itemMessage(msg models.ChatMessage) fyne.CanvasObject { my := repo.User.GetUserInfo(global.DB) var card *widget.Card - if msg.User.ID != my.ID { - card = widget.NewCard("", - fmt.Sprintf("%s %s", msg.Time.Format(time.DateTime), - msg.User.Name), widget.NewLabel(msg.Text)) + if msg.UserID != my.ID { + title := fmt.Sprintf("%s %s", msg.CreateTx.Format(time.DateTime), msg.UserName) + card = widget.NewCard("", "", + container.NewVBox( + widget.NewLabel(title), + newLabel(msg.Text, fyne.TextAlignLeading))) } else { - - title := fmt.Sprintf("%s %s", msg.Time.Format(time.DateTime), "我") + title := fmt.Sprintf("%s %s", msg.CreateTx.Format(time.DateTime), "我") card = widget.NewCard("", "", container.NewVBox( widget.NewLabelWithStyle(title, fyne.TextAlignTrailing, fyne.TextStyle{}), - widget.NewLabelWithStyle(msg.Text, fyne.TextAlignTrailing, fyne.TextStyle{}))) + newLabel(msg.Text, fyne.TextAlignTrailing))) } return card } + +func newLabel(title string, ali fyne.TextAlign) *widget.Label { + text := widget.NewLabelWithStyle(title, ali, fyne.TextStyle{}) + text.Wrapping = fyne.TextWrapBreak + return text +} diff --git a/views/followUsers.go b/views/followUsers.go index 5661290..f5ef775 100644 --- a/views/followUsers.go +++ b/views/followUsers.go @@ -1,6 +1,7 @@ package views import ( + "fmt" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/dialog" @@ -72,6 +73,7 @@ func itemFollowUserView(w fyne.Window, data *models.Online, user *models.UserFol } if err == nil && newUser.Name != user.Name { // 更新用户信息 + fmt.Println("更新用户信息:", user, newUser) repo.UserFollow.UnFollow(global.DB, user) repo.UserFollow.Follow(global.DB, &models.UserFollows{Users: *newUser}) } diff --git a/views/gamesViews.go b/views/gamesViews.go new file mode 100644 index 0000000..ee77fbb --- /dev/null +++ b/views/gamesViews.go @@ -0,0 +1,106 @@ +package views + +import ( + "errors" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" + "slices" + "sync" +) + +func TenChinaGameView() { + myApp := fyne.CurrentApp() + myWindow := myApp.NewWindow("Cross Flag Game") + + gridWrap := container.NewGridWrap(fyne.NewSize(100, 100)) + + for i := 0; i < 9; i++ { + //var itemIndex = i + var item = widget.NewButton("", func() {}) + if i > 6 { + item.SetIcon(theme.ConfirmIcon()) + } else { + item.SetIcon(theme.CancelIcon()) + } + gridWrap.Add(container.NewBorder(nil, nil, nil, nil, item)) + } + myWindow.SetContent(container.NewScroll(gridWrap)) + + myWindow.Resize(fyne.NewSize(320, 318)) + myWindow.CenterOnScreen() + myWindow.Show() +} + +type TenGame struct { + lock sync.Mutex + playerMax int + CurrentRoundPlayer int + players [][]int + items []*widget.Button + winCallback func(int) +} + +func (t *TenGame) Play(userIndex int, pos int) error { + t.lock.Lock() + defer t.lock.Unlock() + if t.CurrentRoundPlayer != userIndex { + return errors.New("not your turn") + } + t.play(pos) + + t.CurrentRoundPlayer++ + if t.CurrentRoundPlayer+1 > t.playerMax { + t.CurrentRoundPlayer = 0 + } + return nil +} + +/* +1, 2, 3 +4, 5, 6 +7, 8, 9 +*/ +func (t *TenGame) play(pos int) { + // TODO + playerIntList := t.players[t.CurrentRoundPlayer] + playerIntList = append(playerIntList, pos) + // 刷新数据 + if t.CurrentRoundPlayer == 1 { + t.items[pos].SetIcon(theme.ConfirmIcon()) + } else { + t.items[pos].SetIcon(theme.CancelIcon()) + } + + // check 胜利 判断 + slices.Sort(playerIntList) + +} + +func (t *TenGame) winCheck(playerIntList []int) bool { + for _, i := range playerIntList { + var iI = i + if t.checkLine(playerIntList, iI, 1) || + t.checkLine(playerIntList, iI, 2) || + t.checkLine(playerIntList, iI, 4) { + return true + } + // todo slices.Delete() + } + + return false +} + +func (t *TenGame) checkLine(playerIntList []int, iI, add int) bool { + for { + iI += add + if iI > 9 { + return true + } + if !slices.Contains(playerIntList, iI) { + return false + } + } + +} diff --git a/views/otherUsers.go b/views/otherUsers.go index 4af3959..172d2e4 100644 --- a/views/otherUsers.go +++ b/views/otherUsers.go @@ -4,7 +4,6 @@ import ( "fmt" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/data/binding" "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" @@ -114,35 +113,12 @@ func baseOtherCardView(w fyne.Window, baseCardCopy models.BaseCard, online *mode baseCardV := widget.NewCard(baseCardCopy.Title, baseCardCopy.Text, container.NewBorder(nil, widget.NewToolbar( widget.NewToolbarAction(theme.DownloadIcon(), func() { b := saveCard.UpdateTx.Unix() == baseCardCopy.UpdateTx.Unix() - fmt.Println(saveCard.UpdateTx, baseCardCopy.UpdateTx) if b { dialog.ShowInformation("结果", "已下载本地", w) return } - // 下载到本地 若没关注自动关注 - - progress := binding.NewFloat() - progress.Set(0) - progressBar := widget.NewProgressBarWithData(progress) - progressBar.Max = 100 - smaillWin := dialog.NewCustom("下载中", "关闭", progressBar, w) - smaillWin.Show() - err := service.Client.Download(online, baseCardCopy.UUID, progress) - if err != nil { - smaillWin.SetDismissText("失败") - return - } - // 修改数据 - progress.Set(99) - saveCard.UpdateTx = baseCardCopy.UpdateTx - err = repo.BaseCard.CreateOrSave(global.DB, &baseCardCopy) - if err != nil { - smaillWin.SetDismissText("失败") - return - } - progress.Set(100) - smaillWin.SetDismissText("完成 请去[我的]查看") - + // 下载到本地 TODO 若没关注自动关注 + service.BaseCard.DownloadCard(w, baseCardCopy, online) }), ), nil, nil, infoWid)) return baseCardV diff --git a/views/userView.go b/views/userView.go index 04119ca..5bb5c8e 100644 --- a/views/userView.go +++ b/views/userView.go @@ -22,6 +22,7 @@ import ( ) func mainUserViews(w fyne.Window) fyne.CanvasObject { + //TenChinaGameView() var userCard = widget.NewCard("", "", nil) user1 := repo.User.GetUserInfo(global.DB) refresh := func(user *models.Users) {