diff --git a/.gitignore b/.gitignore index 54cbb24..75f573e 100644 --- a/.gitignore +++ b/.gitignore @@ -107,6 +107,6 @@ dist .idea/ data/*.db -build/*.exe -/build/bin/go-stock-dev.exe -/build/bin/ +./build/*.exe +./build/bin/go-stock-dev.exe +./build/bin/go-stock.exe diff --git a/app.go b/app.go index 52b3d3e..932aafd 100644 --- a/app.go +++ b/app.go @@ -2,6 +2,8 @@ package main import ( "context" + "github.com/coocood/freecache" + "github.com/getlantern/systray" "github.com/wailsapp/wails/v2/pkg/runtime" "go-stock/backend/data" "go-stock/backend/logger" @@ -9,18 +11,31 @@ import ( // App struct type App struct { - ctx context.Context + ctx context.Context + cache *freecache.Cache } // NewApp creates a new App application struct func NewApp() *App { - return &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 @@ -63,6 +78,7 @@ func (a *App) beforeClose(ctx context.Context) (prevent bool) { // 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 @@ -90,3 +106,59 @@ func (a *App) GetStockList(key string) []data.StockBasic { func (a *App) SetCostPriceAndVolume(stockCode string, price float64, volume int64) string { return data.NewStockDataApi().SetCostPriceAndVolume(price, volume, stockCode) } + +func (a *App) SetAlarmChangePercent(val float64, stockCode string) string { + return data.NewStockDataApi().SetAlarmChangePercent(val, 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) +} + +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("这是一个简单的系统托盘示例") + // 创建菜单项 + mQuitOrig := systray.AddMenuItem("退出", "退出应用程序") + show := systray.AddMenuItem("显示", "显示应用程序") + hide := 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.Show(a.ctx) + //runtime.WindowShow(a.ctx) + case <-hide.ClickedCh: + logger.SugaredLogger.Infof("隐藏应用程序") + runtime.Hide(a.ctx) + + } + } + }() +} diff --git a/backend/data/dingding_api.go b/backend/data/dingding_api.go new file mode 100644 index 0000000..b591373 --- /dev/null +++ b/backend/data/dingding_api.go @@ -0,0 +1,77 @@ +package data + +import ( + "github.com/go-resty/resty/v2" + "go-stock/backend/logger" +) + +// @Author spark +// @Date 2025/1/3 13:53 +// @Desc +//----------------------------------------------------------------------------------- + +const dingding_robot_url = "https://oapi.dingtalk.com/robot/send?access_token=0237527b404598f37ae5d83ef36e936860c7ba5d3892cd43f64c4159d3ed7cb1" + +type DingDingAPI struct { + client *resty.Client +} + +func NewDingDingAPI() *DingDingAPI { + return &DingDingAPI{ + client: resty.New(), + } +} + +func (DingDingAPI) SendDingDingMessage(message string) string { + // 发送钉钉消息 + resp, err := resty.New().R(). + SetHeader("Content-Type", "application/json"). + SetBody(message). + Post(dingding_robot_url) + if err != nil { + logger.SugaredLogger.Error(err.Error()) + return "发送钉钉消息失败" + } + logger.SugaredLogger.Infof("send dingding message: %s", resp.String()) + return "发送钉钉消息成功" +} + +func (DingDingAPI) SendToDingDing(title, message string) string { + // 发送钉钉消息 + resp, err := resty.New().R(). + SetHeader("Content-Type", "application/json"). + SetBody(&Message{ + Msgtype: "markdown", + Markdown: Markdown{ + Title: "go-stock " + title, + Text: message, + }, + At: At{ + IsAtAll: true, + }, + }). + Post(dingding_robot_url) + if err != nil { + logger.SugaredLogger.Error(err.Error()) + return "发送钉钉消息失败" + } + logger.SugaredLogger.Infof("send dingding message: %s", resp.String()) + return "发送钉钉消息成功" +} + +type Message struct { + Msgtype string `json:"msgtype"` + Markdown Markdown `json:"markdown"` + At At `json:"at"` +} + +type Markdown struct { + Title string `json:"title"` + Text string `json:"text"` +} + +type At struct { + AtMobiles []string `json:"atMobiles"` + AtUserIds []string `json:"atUserIds"` + IsAtAll bool `json:"isAtAll"` +} diff --git a/backend/data/dingding_api_test.go b/backend/data/dingding_api_test.go new file mode 100644 index 0000000..72a0e4f --- /dev/null +++ b/backend/data/dingding_api_test.go @@ -0,0 +1,31 @@ +package data + +import ( + "github.com/go-resty/resty/v2" + "testing" +) + +// @Author spark +// @Date 2025/1/3 13:53 +// @Desc +//----------------------------------------------------------------------------------- + +func TestRobot(t *testing.T) { + resp, err := resty.New().R(). + SetHeader("Content-Type", "application/json"). + SetBody(`{ + "msgtype": "markdown", + "markdown": { + "title":"go-stock", + "text": "#### 杭州天气 @150XXXXXXXX \n > 9度,西北风1级,空气良89,相对温度73%\n > ![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png)\n > ###### 10点20分发布 [天气](https://www.dingtalk.com) \n" + }, + "at": { + "isAtAll": true + } + }`). + Post(dingding_robot_url) + if err != nil { + t.Error(err) + } + t.Log(resp.String()) +} diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go index fc8ed9d..9b309ba 100644 --- a/backend/data/stock_data_api.go +++ b/backend/data/stock_data_api.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" "github.com/duke-git/lancet/v2/convertor" + "github.com/duke-git/lancet/v2/slice" "github.com/duke-git/lancet/v2/strutil" "github.com/go-resty/resty/v2" "go-stock/backend/db" @@ -126,16 +127,17 @@ type StockBasic struct { } type FollowedStock struct { - StockCode string - Name string - Volume int64 - CostPrice float64 - Price float64 - PriceChange float64 - ChangePercent float64 - Time time.Time - Sort int64 - IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"` + StockCode string + Name string + Volume int64 + CostPrice float64 + Price float64 + PriceChange float64 + ChangePercent float64 + AlarmChangePercent float64 + Time time.Time + Sort int64 + IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"` } func (receiver FollowedStock) TableName() string { @@ -162,21 +164,68 @@ func NewStockDataApi() *StockDataApi { client: resty.New(), } } + +// GetIndexBasic 获取指数信息 +func (receiver StockDataApi) GetIndexBasic() { + res := &TushareStockBasicResponse{} + fields := "ts_code,name,market,publisher,category,base_date,base_point,list_date,fullname,index_type,weight_rule,desc" + _, err := receiver.client.R(). + SetHeader("content-type", "application/json"). + SetBody(&TushareRequest{ + ApiName: "index_basic", + Token: TushareToken, + Params: nil, + Fields: fields}). + SetResult(res). + Post(tushare_api_url) + if err != nil { + logger.SugaredLogger.Error(err.Error()) + return + } + if res.Code != 0 { + logger.SugaredLogger.Error(res.Msg) + return + } + //ioutil.WriteFile("index_basic.json", resp.Body(), 0666) + + for _, item := range res.Data.Items { + data := map[string]any{} + for _, field := range strings.Split(fields, ",") { + idx := slice.IndexOf(res.Data.Fields, field) + if idx == -1 { + continue + } + data[field] = item[idx] + } + index := &IndexBasic{} + jsonData, _ := json.Marshal(data) + err := json.Unmarshal(jsonData, index) + if err != nil { + continue + } + db.Dao.Model(&IndexBasic{}).FirstOrCreate(index, &IndexBasic{TsCode: index.TsCode}).Where("ts_code = ?", index.TsCode).Updates(index) + } + +} + +// map转换为结构体 + func (receiver StockDataApi) GetStockBaseInfo() { res := &TushareStockBasicResponse{} - resp, err := receiver.client.R(). + fields := "ts_code,symbol,name,area,industry,cnspell,market,list_date,act_name,act_ent_type,fullname,exchange,list_status,curr_type,enname,delist_date,is_hs" + _, err := receiver.client.R(). SetHeader("content-type", "application/json"). SetBody(&TushareRequest{ ApiName: "stock_basic", Token: TushareToken, Params: nil, - Fields: "*", + Fields: fields, }). SetResult(res). Post(tushare_api_url) //logger.SugaredLogger.Infof("GetStockBaseInfo %s", string(resp.Body())) //resp.Body()写入文件 - ioutil.WriteFile("stock_basic.json", resp.Body(), 0666) + //ioutil.WriteFile("stock_basic.json", resp.Body(), 0666) //logger.SugaredLogger.Infof("GetStockBaseInfo %+v", res) if err != nil { logger.SugaredLogger.Error(err.Error()) @@ -187,26 +236,22 @@ func (receiver StockDataApi) GetStockBaseInfo() { return } for _, item := range res.Data.Items { - ID, _ := convertor.ToInt(item[6]) stock := &StockBasic{} - stock.Exchange = convertor.ToString(item[0]) - stock.IsHs = convertor.ToString(item[1]) - stock.Name = convertor.ToString(item[2]) - stock.Industry = convertor.ToString(item[3]) - stock.ListStatus = convertor.ToString(item[4]) - stock.ActName = convertor.ToString(item[5]) - stock.ID = uint(ID) - stock.CurrType = convertor.ToString(item[7]) - stock.Area = convertor.ToString(item[8]) - stock.ListDate = convertor.ToString(item[9]) - stock.DelistDate = convertor.ToString(item[10]) - stock.ActEntType = convertor.ToString(item[11]) - stock.TsCode = convertor.ToString(item[12]) - stock.Symbol = convertor.ToString(item[13]) - stock.Cnspell = convertor.ToString(item[14]) - stock.Fullname = convertor.ToString(item[20]) - stock.Ename = convertor.ToString(item[21]) - db.Dao.Model(&StockBasic{}).FirstOrCreate(stock, &StockBasic{TsCode: stock.TsCode}).Updates(stock) + data := map[string]any{} + for _, field := range strings.Split(fields, ",") { + logger.SugaredLogger.Infof("field: %s", field) + idx := slice.IndexOf(res.Data.Fields, field) + if idx == -1 { + continue + } + data[field] = item[idx] + } + jsonData, _ := json.Marshal(data) + err := json.Unmarshal(jsonData, stock) + if err != nil { + continue + } + db.Dao.Model(&StockBasic{}).FirstOrCreate(stock, &StockBasic{TsCode: stock.TsCode}).Where("ts_code = ?", stock.TsCode).Updates(stock) } } @@ -233,6 +278,7 @@ func (receiver StockDataApi) GetStockCodeRealTimeData(StockCode string) (*StockI } func (receiver StockDataApi) Follow(stockCode string) string { + logger.SugaredLogger.Infof("Follow %s", stockCode) stockInfo, err := receiver.GetStockCodeRealTimeData(stockCode) if err != nil { logger.SugaredLogger.Error(err.Error()) @@ -264,6 +310,15 @@ func (receiver StockDataApi) SetCostPriceAndVolume(price float64, volume int64, return "设置成功" } +func (receiver StockDataApi) SetAlarmChangePercent(val float64, stockCode string) string { + err := db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", stockCode).Update("alarm_change_percent", val).Error + if err != nil { + logger.SugaredLogger.Error(err.Error()) + return "设置失败" + } + return "设置成功" +} + func (receiver StockDataApi) GetFollowList() []FollowedStock { var result []FollowedStock db.Dao.Model(&FollowedStock{}).Order("sort asc,time desc").Find(&result) @@ -273,6 +328,20 @@ func (receiver StockDataApi) GetFollowList() []FollowedStock { func (receiver StockDataApi) GetStockList(key string) []StockBasic { var result []StockBasic db.Dao.Model(&StockBasic{}).Where("name like ? or ts_code like ?", "%"+key+"%", "%"+key+"%").Find(&result) + var result2 []IndexBasic + db.Dao.Model(&IndexBasic{}).Where("market in ?", []string{"SSE", "SZSE"}).Where("name like ? or ts_code like ?", "%"+key+"%", "%"+key+"%").Find(&result2) + + for _, item := range result2 { + result = append(result, StockBasic{ + TsCode: item.TsCode, + Name: item.Name, + Fullname: item.FullName, + Symbol: item.Symbol, + Market: item.Market, + ListDate: item.ListDate, + }) + } + return result } @@ -371,3 +440,24 @@ func ParseFullSingleStockData(data string) (*StockInfo, error) { return stockInfo, nil } + +type IndexBasic struct { + gorm.Model + TsCode string `json:"ts_code" gorm:"index"` + Symbol string `json:"symbol" gorm:"index"` + Name string `json:"name" gorm:"index"` + FullName string `json:"fullname"` + IndexType string `json:"index_type"` + IndexCategory string `json:"category"` + Market string `json:"market"` + ListDate string `json:"list_date"` + BaseDate string `json:"base_date"` + BasePoint float64 `json:"base_point"` + Publisher string `json:"publisher"` + WeightRule string `json:"weight_rule"` + DESC string `json:"desc"` +} + +func (IndexBasic) TableName() string { + return "tushare_index_basic" +} diff --git a/backend/data/stock_data_api_test.go b/backend/data/stock_data_api_test.go index 7e88a64..6d5ca87 100644 --- a/backend/data/stock_data_api_test.go +++ b/backend/data/stock_data_api_test.go @@ -77,3 +77,9 @@ func TestFollowedList(t *testing.T) { t.Log(stockDataApi.GetFollowList()) } + +func TestStockDataApi_GetIndexBasic(t *testing.T) { + db.Init("../../data/stock.db") + stockDataApi := NewStockDataApi() + stockDataApi.GetIndexBasic() +} diff --git a/build/app.ico b/build/app.ico new file mode 100644 index 0000000..b261d41 Binary files /dev/null and b/build/app.ico differ diff --git a/build/bin/go-stock.exe b/build/bin/go-stock.exe deleted file mode 100644 index 511db66..0000000 Binary files a/build/bin/go-stock.exe and /dev/null differ diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue index 739098c..ec2203f 100644 --- a/frontend/src/components/stock.vue +++ b/frontend/src/components/stock.vue @@ -1,6 +1,14 @@ @@ -305,8 +369,8 @@ function fullscreen(){ autocomplete: 'disabled', }" :options="options" - placeholder="请输入股票名称或者代码" - clearable @input="getStockList" :on-select="onSelect"/> + placeholder="请输入股票/指数名称或者代码" + clearable @update-value="getStockList" :on-select="onSelect"/>  关注该股票 @@ -315,16 +379,31 @@ function fullscreen(){ - - - + + + + + - - + + + + + + + + + diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index 11f153e..150cab0 100644 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -10,6 +10,10 @@ export function GetStockList(arg1:string):Promise>; export function Greet(arg1:string):Promise; +export function SendDingDingMessage(arg1:string,arg2:string):Promise; + +export function SetAlarmChangePercent(arg1:number,arg2:string):Promise; + export function SetCostPriceAndVolume(arg1:string,arg2:number,arg3:number):Promise; export function UnFollow(arg1:string):Promise; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index e7396db..745ac69 100644 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -18,6 +18,14 @@ export function Greet(arg1) { return window['go']['main']['App']['Greet'](arg1); } +export function SendDingDingMessage(arg1, arg2) { + return window['go']['main']['App']['SendDingDingMessage'](arg1, arg2); +} + +export function SetAlarmChangePercent(arg1, arg2) { + return window['go']['main']['App']['SetAlarmChangePercent'](arg1, arg2); +} + export function SetCostPriceAndVolume(arg1, arg2, arg3) { return window['go']['main']['App']['SetCostPriceAndVolume'](arg1, arg2, arg3); } diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts index 96143c8..b01da60 100644 --- a/frontend/wailsjs/go/models.ts +++ b/frontend/wailsjs/go/models.ts @@ -8,6 +8,7 @@ export namespace data { Price: number; PriceChange: number; ChangePercent: number; + AlarmChangePercent: number; // Go type: time Time: any; Sort: number; @@ -26,6 +27,7 @@ export namespace data { this.Price = source["Price"]; this.PriceChange = source["PriceChange"]; this.ChangePercent = source["ChangePercent"]; + this.AlarmChangePercent = source["AlarmChangePercent"]; this.Time = this.convertValues(source["Time"], null); this.Sort = source["Sort"]; this.IsDel = source["IsDel"]; diff --git a/go.mod b/go.mod index 174e3d0..8843abf 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,9 @@ go 1.21 toolchain go1.23.0 require ( + github.com/coocood/freecache v1.2.4 github.com/duke-git/lancet/v2 v2.3.4 + 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/wailsapp/wails/v2 v2.9.2 @@ -19,9 +21,17 @@ require ( require ( github.com/bep/debounce v1.2.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect + github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect + github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect + github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect + github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect + github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-stack/stack v1.8.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect @@ -35,6 +45,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/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 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect diff --git a/go.sum b/go.sum index eb769d9..a64c8c2 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/coocood/freecache v1.2.4 h1:UdR6Yz/X1HW4fZOuH0Z94KwG851GWOSknua5VUbb/5M= +github.com/coocood/freecache v1.2.4/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -7,6 +11,20 @@ github.com/duke-git/lancet/v2 v2.3.4 h1:8XGI7P9w+/GqmEBEXYaH/XuNiM0f4/90Ioti0IvY github.com/duke-git/lancet/v2 v2.3.4/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4= +github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA= +github.com/getlantern/systray v1.2.2 h1:dCEHtfmvkJG7HZ8lS/sLklTH4RKUcIsKrAD9sThoEBE= +github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgNMY5HvhHhcE= github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= @@ -17,6 +35,8 @@ github.com/go-resty/resty/v2 v2.16.2 h1:CpRqTjIzq/rweXUt9+GxzzQdlkqMdt8Lm/fuK/CA github.com/go-resty/resty/v2 v2.16.2/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= 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/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= @@ -46,6 +66,8 @@ github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/ github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI= github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= +github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -58,6 +80,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/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= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -72,7 +96,9 @@ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -117,6 +143,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -127,6 +154,7 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= @@ -149,6 +177,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= diff --git a/main.go b/main.go index 3e5e2fe..a384fda 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,9 @@ var assets embed.FS //go:embed build/appicon.png var icon []byte +//go:embed build/app.ico +var icon2 []byte + //go:embed build/stock_basic.json var stocksBin []byte @@ -35,11 +38,13 @@ func main() { db.Dao.AutoMigrate(&data.StockInfo{}) db.Dao.AutoMigrate(&data.StockBasic{}) db.Dao.AutoMigrate(&data.FollowedStock{}) + db.Dao.AutoMigrate(&data.IndexBasic{}) if stocksBin != nil && len(stocksBin) > 0 { go initStockData() } go data.NewStockDataApi().GetStockBaseInfo() + go data.NewStockDataApi().GetIndexBasic() // Create an instance of the app structure app := NewApp() @@ -63,9 +68,13 @@ func main() { FileMenu.AddText("窗口还原", keys.Key("Esc"), func(callback *menu.CallbackData) { runtime.WindowUnfullscreen(app.ctx) }) + FileMenu.AddText("隐藏到托盘区", keys.CmdOrCtrl("h"), func(_ *menu.CallbackData) { + runtime.Hide(app.ctx) + }) FileMenu.AddText("退出", keys.CmdOrCtrl("q"), func(_ *menu.CallbackData) { runtime.Quit(app.ctx) }) + // Create application with options err := wails.Run(&options.App{ Title: "go-stock", diff --git a/stock_basic.json b/stock_basic.json deleted file mode 100644 index c9a1711..0000000 --- a/stock_basic.json +++ /dev/null @@ -1 +0,0 @@ -{"request_id":"bf5b7774-d16d-43fe-9806-dff9ef37cd33","code":40203,"data":null,"msg":"抱歉,您每小时最多访问该接口1次,权限的具体详情访问:https://tushare.pro/document/1?doc_id=108。"} \ No newline at end of file