mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
- 新增 AlertWindowsApi 结构体和 SendNotification 方法,用于发送 Windows 系统通知 - 实现 SendDingDingMessageByType 方法,支持根据不同消息类型发送通知 - 添加消息类型 TTL 和名称映射,优化消息发送逻辑 - 更新前端接口,增加 SendDingDingMessageByType 方法调用- 引入 go-toast 库,用于 Windows 系统通知
240 lines
6.2 KiB
Go
240 lines
6.2 KiB
Go
//go:build windows
|
|
|
|
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"
|
|
)
|
|
|
|
// App struct
|
|
type App struct {
|
|
ctx context.Context
|
|
cache *freecache.Cache
|
|
}
|
|
|
|
// NewApp creates a new App application struct
|
|
func NewApp() *App {
|
|
cacheSize := 512 * 1024
|
|
cache := freecache.NewCache(cacheSize)
|
|
return &App{
|
|
cache: cache,
|
|
}
|
|
}
|
|
|
|
// startup is called at application startup
|
|
func (a *App) startup(ctx context.Context) {
|
|
// Perform your setup here
|
|
a.ctx = ctx
|
|
|
|
// 创建系统托盘
|
|
go systray.Run(func() {
|
|
onReady(a)
|
|
}, func() {
|
|
onExit(a)
|
|
})
|
|
|
|
}
|
|
|
|
// domReady is called after front-end resources have been loaded
|
|
func (a *App) domReady(ctx context.Context) {
|
|
// Add your action here
|
|
//ticker := time.NewTicker(time.Second)
|
|
//defer ticker.Stop()
|
|
////定时更新数据
|
|
//go func() {
|
|
// for range ticker.C {
|
|
// runtime.WindowSetTitle(ctx, "go-stock "+time.Now().Format("2006-01-02 15:04:05"))
|
|
// }
|
|
//}()
|
|
}
|
|
|
|
// beforeClose is called when the application is about to quit,
|
|
// either by clicking the window close button or calling runtime.Quit.
|
|
// Returning true will cause the application to continue, false will continue shutdown as normal.
|
|
func (a *App) beforeClose(ctx context.Context) (prevent bool) {
|
|
|
|
dialog, err := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{
|
|
Type: runtime.QuestionDialog,
|
|
Title: "go-stock",
|
|
Message: "确定关闭吗?",
|
|
Buttons: []string{"确定"},
|
|
Icon: icon,
|
|
CancelButton: "取消",
|
|
})
|
|
|
|
if err != nil {
|
|
logger.SugaredLogger.Errorf("dialog error:%s", err.Error())
|
|
return false
|
|
}
|
|
logger.SugaredLogger.Debugf("dialog:%s", dialog)
|
|
if dialog == "No" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// shutdown is called at application termination
|
|
func (a *App) shutdown(ctx context.Context) {
|
|
// Perform your teardown here
|
|
systray.Quit()
|
|
}
|
|
|
|
// Greet returns a greeting for the given name
|
|
func (a *App) Greet(name string) *data.StockInfo {
|
|
stockInfo, _ := data.NewStockDataApi().GetStockCodeRealTimeData(name)
|
|
return stockInfo
|
|
}
|
|
|
|
func (a *App) Follow(stockCode string) string {
|
|
return data.NewStockDataApi().Follow(stockCode)
|
|
}
|
|
|
|
func (a *App) UnFollow(stockCode string) string {
|
|
return data.NewStockDataApi().UnFollow(stockCode)
|
|
}
|
|
|
|
func (a *App) GetFollowList() []data.FollowedStock {
|
|
return data.NewStockDataApi().GetFollowList()
|
|
}
|
|
|
|
func (a *App) GetStockList(key string) []data.StockBasic {
|
|
return data.NewStockDataApi().GetStockList(key)
|
|
}
|
|
|
|
func (a *App) SetCostPriceAndVolume(stockCode string, price float64, volume int64) string {
|
|
return data.NewStockDataApi().SetCostPriceAndVolume(price, volume, stockCode)
|
|
}
|
|
|
|
func (a *App) SetAlarmChangePercent(val, alarmPrice float64, stockCode string) string {
|
|
return data.NewStockDataApi().SetAlarmChangePercent(val, alarmPrice, stockCode)
|
|
}
|
|
func (a *App) SetStockSort(sort int64, stockCode string) {
|
|
data.NewStockDataApi().SetStockSort(sort, stockCode)
|
|
}
|
|
func (a *App) SendDingDingMessage(message string, stockCode string) 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"), 60*5)
|
|
if err != nil {
|
|
logger.SugaredLogger.Errorf("set cache error:%s", err.Error())
|
|
return ""
|
|
}
|
|
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")
|
|
runtime.Quit(a.ctx)
|
|
}
|
|
|
|
func onReady(a *App) {
|
|
|
|
// 初始化操作
|
|
logger.SugaredLogger.Infof("onReady")
|
|
systray.SetIcon(icon2)
|
|
systray.SetTitle("go-stock")
|
|
systray.SetTooltip("go-stock 股票行情实时获取")
|
|
|
|
// 创建菜单项
|
|
show := systray.AddMenuItem("显示", "显示应用程序")
|
|
//hide := systray.AddMenuItem("隐藏", "隐藏应用程序")
|
|
systray.AddSeparator()
|
|
mQuitOrig := systray.AddMenuItem("退出", "退出应用程序")
|
|
|
|
// 监听菜单项点击事件
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-mQuitOrig.ClickedCh:
|
|
logger.SugaredLogger.Infof("退出应用程序")
|
|
runtime.Quit(a.ctx)
|
|
//systray.Quit()
|
|
case <-show.ClickedCh:
|
|
logger.SugaredLogger.Infof("显示应用程序")
|
|
runtime.WindowShow(a.ctx)
|
|
//runtime.WindowShow(a.ctx)
|
|
//case <-hide.ClickedCh:
|
|
// logger.SugaredLogger.Infof("隐藏应用程序")
|
|
// runtime.Hide(a.ctx)
|
|
|
|
}
|
|
}
|
|
}()
|
|
}
|