diff --git a/app.go b/app.go index a9ab9bb..8cfdbb6 100644 --- a/app.go +++ b/app.go @@ -5,9 +5,12 @@ package main import ( "context" "github.com/coocood/freecache" + "github.com/duke-git/lancet/v2/convertor" + "github.com/duke-git/lancet/v2/mathutil" "github.com/getlantern/systray" "github.com/wailsapp/wails/v2/pkg/runtime" "go-stock/backend/data" + "go-stock/backend/db" "go-stock/backend/logger" ) @@ -130,6 +133,70 @@ func (a *App) SendDingDingMessage(message string, stockCode string) string { return data.NewDingDingAPI().SendDingDingMessage(message) } +// SendDingDingMessageByType msgType 报警类型: 1 涨跌报警;2 股价报警 3 成本价报警 +func (a *App) SendDingDingMessageByType(message string, stockCode string, msgType int) string { + ttl, _ := a.cache.TTL([]byte(stockCode)) + logger.SugaredLogger.Infof("stockCode %s ttl:%d", stockCode, ttl) + if ttl > 0 { + return "" + } + err := a.cache.Set([]byte(stockCode), []byte("1"), getMsgTypeTTL(msgType)) + if err != nil { + logger.SugaredLogger.Errorf("set cache error:%s", err.Error()) + return "" + } + stockInfo := &data.StockInfo{} + db.Dao.Model(stockInfo).Where("code = ?", stockCode).First(stockInfo) + if !data.NewAlertWindowsApi("go-stock消息通知", getMsgTypeName(msgType), GenNotificationMsg(stockInfo), "").SendNotification() { + return data.NewDingDingAPI().SendDingDingMessage(message) + } + return "发送系统消息成功" +} + +func GenNotificationMsg(stockInfo *data.StockInfo) string { + Price, err := convertor.ToFloat(stockInfo.Price) + if err != nil { + Price = 0 + } + PreClose, err := convertor.ToFloat(stockInfo.PreClose) + if err != nil { + PreClose = 0 + } + var RF float64 + if PreClose > 0 { + RF = mathutil.RoundToFloat(((Price-PreClose)/PreClose)*100, 2) + } + + return "[" + stockInfo.Name + "] " + stockInfo.Price + " " + convertor.ToString(RF) + "% " + stockInfo.Date + " " + stockInfo.Time +} + +// msgType : 1 涨跌报警(5分钟);2 股价报警(30分钟) 3 成本价报警(30分钟) +func getMsgTypeTTL(msgType int) int { + switch msgType { + case 1: + return 60 * 5 + case 2: + return 60 * 30 + case 3: + return 60 * 30 + default: + return 60 * 5 + } +} + +func getMsgTypeName(msgType int) string { + switch msgType { + case 1: + return "涨跌报警" + case 2: + return "股价报警" + case 3: + return "成本价报警" + default: + return "未知类型" + } +} + func onExit(a *App) { // 清理操作 logger.SugaredLogger.Infof("onExit") diff --git a/backend/data/alert_windows_api.go b/backend/data/alert_windows_api.go new file mode 100644 index 0000000..e2ed65a --- /dev/null +++ b/backend/data/alert_windows_api.go @@ -0,0 +1,48 @@ +//go:build windows + +package data + +import ( + "github.com/go-toast/toast" + "go-stock/backend/logger" +) + +// AlertWindowsApi @Author spark +// @Date 2025/1/8 9:40 +// @Desc +// ----------------------------------------------------------------------------------- +type alertWindowsApi struct { + AppID string + // 窗口标题 + Title string + // 窗口内容 + Content string + // 窗口图标 + Icon string +} + +func NewAlertWindowsApi(AppID string, Title string, Content string, Icon string) *alertWindowsApi { + return &alertWindowsApi{ + AppID: AppID, + Title: Title, + Content: Content, + Icon: Icon, + } +} + +func (a alertWindowsApi) SendNotification() bool { + notification := toast.Notification{ + AppID: a.AppID, + Title: a.Title, + Message: a.Content, + Icon: a.Icon, + Duration: "short", + Audio: toast.Default, + } + err := notification.Push() + if err != nil { + logger.SugaredLogger.Error(err) + return false + } + return true +} diff --git a/backend/data/alert_windows_api_test.go b/backend/data/alert_windows_api_test.go new file mode 100644 index 0000000..3142383 --- /dev/null +++ b/backend/data/alert_windows_api_test.go @@ -0,0 +1,30 @@ +//go:build windows + +package data + +import ( + "github.com/go-toast/toast" + "go-stock/backend/logger" + "testing" +) + +// @Author spark +// @Date 2025/1/8 9:40 +// @Desc +//----------------------------------------------------------------------------------- + +func TestAlert(t *testing.T) { + notification := toast.Notification{ + AppID: "go-stock", + Title: "Hello, World!", + Message: "This is a toast notification.", + Icon: "../../build/appicon.png", + Duration: "short", + Audio: toast.Default, + } + err := notification.Push() + if err != nil { + logger.SugaredLogger.Error(err) + return + } +} diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue index dede916..3e0e3eb 100644 --- a/frontend/src/components/stock.vue +++ b/frontend/src/components/stock.vue @@ -5,7 +5,7 @@ import { GetFollowList, GetStockList, Greet, - SendDingDingMessage, + SendDingDingMessage, SendDingDingMessageByType, SetAlarmChangePercent, SetCostPriceAndVolume, SetStockSort, UnFollow @@ -361,7 +361,8 @@ function SendMessage(result,type){ ' "isAtAll": true' + ' }' + ' }' - SendDingDingMessage(msg,result["股票代码"]) + // SendDingDingMessage(msg,result["股票代码"]) + SendDingDingMessageByType(msg,result["股票代码"],type) } function getTypeName(type){ diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index 338298f..e7c8dc3 100644 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -12,6 +12,8 @@ export function Greet(arg1:string):Promise; export function SendDingDingMessage(arg1:string,arg2:string):Promise; +export function SendDingDingMessageByType(arg1:string,arg2:string,arg3:number):Promise; + export function SetAlarmChangePercent(arg1:number,arg2:number,arg3:string):Promise; export function SetCostPriceAndVolume(arg1:string,arg2:number,arg3:number):Promise; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index 3fe45f9..06097eb 100644 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -22,6 +22,10 @@ export function SendDingDingMessage(arg1, arg2) { return window['go']['main']['App']['SendDingDingMessage'](arg1, arg2); } +export function SendDingDingMessageByType(arg1, arg2, arg3) { + return window['go']['main']['App']['SendDingDingMessageByType'](arg1, arg2, arg3); +} + export function SetAlarmChangePercent(arg1, arg2, arg3) { return window['go']['main']['App']['SetAlarmChangePercent'](arg1, arg2, arg3); } diff --git a/go.mod b/go.mod index 8843abf..f4b35ea 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/getlantern/systray v1.2.2 github.com/glebarez/sqlite v1.11.0 github.com/go-resty/resty/v2 v2.16.2 + github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 github.com/wailsapp/wails/v2 v2.9.2 go.uber.org/zap v1.27.0 golang.org/x/text v0.16.0 @@ -45,6 +46,7 @@ require ( github.com/leaanthony/u v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect + github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index a64c8c2..d1e8764 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,8 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE= +github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= @@ -80,6 +82,8 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= +github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=