# Conflicts:
#	stock_basic.json
This commit is contained in:
sparkmemory 2025-01-03 23:03:40 +08:00
commit 1e5d9bc469
16 changed files with 474 additions and 57 deletions

6
.gitignore vendored
View File

@ -107,6 +107,6 @@ dist
.idea/ .idea/
data/*.db data/*.db
build/*.exe ./build/*.exe
/build/bin/go-stock-dev.exe ./build/bin/go-stock-dev.exe
/build/bin/ ./build/bin/go-stock.exe

76
app.go
View File

@ -2,6 +2,8 @@ package main
import ( import (
"context" "context"
"github.com/coocood/freecache"
"github.com/getlantern/systray"
"github.com/wailsapp/wails/v2/pkg/runtime" "github.com/wailsapp/wails/v2/pkg/runtime"
"go-stock/backend/data" "go-stock/backend/data"
"go-stock/backend/logger" "go-stock/backend/logger"
@ -9,18 +11,31 @@ import (
// App struct // App struct
type App struct { type App struct {
ctx context.Context ctx context.Context
cache *freecache.Cache
} }
// NewApp creates a new App application struct // NewApp creates a new App application struct
func NewApp() *App { func NewApp() *App {
return &App{} cacheSize := 512 * 1024
cache := freecache.NewCache(cacheSize)
return &App{
cache: cache,
}
} }
// startup is called at application startup // startup is called at application startup
func (a *App) startup(ctx context.Context) { func (a *App) startup(ctx context.Context) {
// Perform your setup here // Perform your setup here
a.ctx = ctx a.ctx = ctx
// 创建系统托盘
go systray.Run(func() {
onReady(a)
}, func() {
onExit(a)
})
} }
// domReady is called after front-end resources have been loaded // 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 // shutdown is called at application termination
func (a *App) shutdown(ctx context.Context) { func (a *App) shutdown(ctx context.Context) {
// Perform your teardown here // Perform your teardown here
systray.Quit()
} }
// Greet returns a greeting for the given name // 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 { func (a *App) SetCostPriceAndVolume(stockCode string, price float64, volume int64) string {
return data.NewStockDataApi().SetCostPriceAndVolume(price, volume, stockCode) 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)
}
}
}()
}

View File

@ -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"`
}

View File

@ -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())
}

View File

@ -9,6 +9,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/duke-git/lancet/v2/convertor" "github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/slice"
"github.com/duke-git/lancet/v2/strutil" "github.com/duke-git/lancet/v2/strutil"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"go-stock/backend/db" "go-stock/backend/db"
@ -126,16 +127,17 @@ type StockBasic struct {
} }
type FollowedStock struct { type FollowedStock struct {
StockCode string StockCode string
Name string Name string
Volume int64 Volume int64
CostPrice float64 CostPrice float64
Price float64 Price float64
PriceChange float64 PriceChange float64
ChangePercent float64 ChangePercent float64
Time time.Time AlarmChangePercent float64
Sort int64 Time time.Time
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"` Sort int64
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
} }
func (receiver FollowedStock) TableName() string { func (receiver FollowedStock) TableName() string {
@ -162,21 +164,68 @@ func NewStockDataApi() *StockDataApi {
client: resty.New(), 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() { func (receiver StockDataApi) GetStockBaseInfo() {
res := &TushareStockBasicResponse{} 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"). SetHeader("content-type", "application/json").
SetBody(&TushareRequest{ SetBody(&TushareRequest{
ApiName: "stock_basic", ApiName: "stock_basic",
Token: TushareToken, Token: TushareToken,
Params: nil, Params: nil,
Fields: "*", Fields: fields,
}). }).
SetResult(res). SetResult(res).
Post(tushare_api_url) Post(tushare_api_url)
//logger.SugaredLogger.Infof("GetStockBaseInfo %s", string(resp.Body())) //logger.SugaredLogger.Infof("GetStockBaseInfo %s", string(resp.Body()))
//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) //logger.SugaredLogger.Infof("GetStockBaseInfo %+v", res)
if err != nil { if err != nil {
logger.SugaredLogger.Error(err.Error()) logger.SugaredLogger.Error(err.Error())
@ -187,26 +236,22 @@ func (receiver StockDataApi) GetStockBaseInfo() {
return return
} }
for _, item := range res.Data.Items { for _, item := range res.Data.Items {
ID, _ := convertor.ToInt(item[6])
stock := &StockBasic{} stock := &StockBasic{}
stock.Exchange = convertor.ToString(item[0]) data := map[string]any{}
stock.IsHs = convertor.ToString(item[1]) for _, field := range strings.Split(fields, ",") {
stock.Name = convertor.ToString(item[2]) logger.SugaredLogger.Infof("field: %s", field)
stock.Industry = convertor.ToString(item[3]) idx := slice.IndexOf(res.Data.Fields, field)
stock.ListStatus = convertor.ToString(item[4]) if idx == -1 {
stock.ActName = convertor.ToString(item[5]) continue
stock.ID = uint(ID) }
stock.CurrType = convertor.ToString(item[7]) data[field] = item[idx]
stock.Area = convertor.ToString(item[8]) }
stock.ListDate = convertor.ToString(item[9]) jsonData, _ := json.Marshal(data)
stock.DelistDate = convertor.ToString(item[10]) err := json.Unmarshal(jsonData, stock)
stock.ActEntType = convertor.ToString(item[11]) if err != nil {
stock.TsCode = convertor.ToString(item[12]) continue
stock.Symbol = convertor.ToString(item[13]) }
stock.Cnspell = convertor.ToString(item[14]) db.Dao.Model(&StockBasic{}).FirstOrCreate(stock, &StockBasic{TsCode: stock.TsCode}).Where("ts_code = ?", stock.TsCode).Updates(stock)
stock.Fullname = convertor.ToString(item[20])
stock.Ename = convertor.ToString(item[21])
db.Dao.Model(&StockBasic{}).FirstOrCreate(stock, &StockBasic{TsCode: stock.TsCode}).Updates(stock)
} }
} }
@ -233,6 +278,7 @@ func (receiver StockDataApi) GetStockCodeRealTimeData(StockCode string) (*StockI
} }
func (receiver StockDataApi) Follow(stockCode string) string { func (receiver StockDataApi) Follow(stockCode string) string {
logger.SugaredLogger.Infof("Follow %s", stockCode)
stockInfo, err := receiver.GetStockCodeRealTimeData(stockCode) stockInfo, err := receiver.GetStockCodeRealTimeData(stockCode)
if err != nil { if err != nil {
logger.SugaredLogger.Error(err.Error()) logger.SugaredLogger.Error(err.Error())
@ -264,6 +310,15 @@ func (receiver StockDataApi) SetCostPriceAndVolume(price float64, volume int64,
return "设置成功" 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 { func (receiver StockDataApi) GetFollowList() []FollowedStock {
var result []FollowedStock var result []FollowedStock
db.Dao.Model(&FollowedStock{}).Order("sort asc,time desc").Find(&result) 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 { func (receiver StockDataApi) GetStockList(key string) []StockBasic {
var result []StockBasic var result []StockBasic
db.Dao.Model(&StockBasic{}).Where("name like ? or ts_code like ?", "%"+key+"%", "%"+key+"%").Find(&result) 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 return result
} }
@ -371,3 +440,24 @@ func ParseFullSingleStockData(data string) (*StockInfo, error) {
return stockInfo, nil 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"
}

View File

@ -77,3 +77,9 @@ func TestFollowedList(t *testing.T) {
t.Log(stockDataApi.GetFollowList()) t.Log(stockDataApi.GetFollowList())
} }
func TestStockDataApi_GetIndexBasic(t *testing.T) {
db.Init("../../data/stock.db")
stockDataApi := NewStockDataApi()
stockDataApi.GetIndexBasic()
}

BIN
build/app.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

View File

@ -1,6 +1,14 @@
<script setup> <script setup>
import {onBeforeMount, onBeforeUnmount, onMounted, reactive, ref} from 'vue' import {onBeforeMount, onBeforeUnmount, onMounted, reactive, ref} from 'vue'
import {Greet, Follow, UnFollow, GetFollowList, GetStockList, SetCostPriceAndVolume} from '../../wailsjs/go/main/App' import {
Greet,
Follow,
UnFollow,
GetFollowList,
GetStockList,
SetCostPriceAndVolume,
SendDingDingMessage, SetAlarmChangePercent
} from '../../wailsjs/go/main/App'
import {NButton, NFlex, NForm, NFormItem, NInputNumber, NText, useMessage, useModal} from 'naive-ui' import {NButton, NFlex, NForm, NFormItem, NInputNumber, NText, useMessage, useModal} from 'naive-ui'
import { WindowFullscreen,WindowUnfullscreen,EventsOn } from '../../wailsjs/runtime' import { WindowFullscreen,WindowUnfullscreen,EventsOn } from '../../wailsjs/runtime'
import {Add, StarOutline} from '@vicons/ionicons5' import {Add, StarOutline} from '@vicons/ionicons5'
@ -22,7 +30,8 @@ const formModel = ref({
name: "", name: "",
code: "", code: "",
costPrice: 0.000, costPrice: 0.000,
volume: 0 volume: 0,
alarm: 0,
}) })
const data = reactive({ const data = reactive({
@ -40,7 +49,7 @@ onBeforeMount(()=>{
stockList.value = result stockList.value = result
options.value=result.map(item => { options.value=result.map(item => {
return { return {
label: item.name+" "+item.ts_code, label: item.name+" - "+item.ts_code,
value: item.ts_code value: item.ts_code
} }
}) })
@ -64,8 +73,9 @@ onMounted(() => {
ticker.value=setInterval(() => { ticker.value=setInterval(() => {
if(isTradingTime()){ if(isTradingTime()){
monitor() monitor()
data.fenshiURL='http://image.sinajs.cn/newchart/min/n/'+data.code+'.gif'+"?t="+Date.now()
} }
}, 3000) }, 3500)
}) })
@ -123,8 +133,10 @@ function AddStock(){
Follow(data.code).then(result => { Follow(data.code).then(result => {
message.success(result) message.success(result)
}) })
monitor()
}else{
message.error("已经关注了")
} }
monitor()
} }
@ -138,21 +150,29 @@ function removeMonitor(code,name) {
}) })
} }
function getStockList(){ function getStockList(value){
console.log("getStockList",value)
let result; let result;
result=stockList.value.filter(item => item.name.includes(data.name)||item.ts_code.includes(data.name)) result=stockList.value.filter(item => item.name.includes(data.name)||item.ts_code.includes(data.name))
options.value=result.map(item => { options.value=result.map(item => {
return { return {
label: item.name+" "+item.ts_code, label: item.name+" - "+item.ts_code,
value: item.ts_code value: item.ts_code
} }
}) })
if(value&&value.indexOf("-")<=0){
data.code=value
}
} }
async function monitor() { async function monitor() {
for (let code of stocks.value) { for (let code of stocks.value) {
// console.log(code) // console.log(code)
Greet(code).then(result => { Greet(code).then(result => {
if(result["当前价格"]<=0){
result["当前价格"]=result["卖一报价"]
}
let s=(result["当前价格"]-result["昨日收盘价"])*100/result["昨日收盘价"] let s=(result["当前价格"]-result["昨日收盘价"])*100/result["昨日收盘价"]
let roundedNum = s.toFixed(2); // let roundedNum = s.toFixed(2); //
result.s=roundedNum+"%" result.s=roundedNum+"%"
@ -160,7 +180,6 @@ async function monitor() {
result.highRate=((result["今日最高价"]-result["今日开盘价"])*100/result["今日开盘价"]).toFixed(2)+"%" result.highRate=((result["今日最高价"]-result["今日开盘价"])*100/result["今日开盘价"]).toFixed(2)+"%"
result.lowRate=((result["今日最低价"]-result["今日开盘价"])*100/result["今日开盘价"]).toFixed(2)+"%" result.lowRate=((result["今日最低价"]-result["今日开盘价"])*100/result["今日开盘价"]).toFixed(2)+"%"
if (roundedNum>0) { if (roundedNum>0) {
result.type="error" result.type="error"
result.color="#E88080" result.color="#E88080"
@ -173,6 +192,7 @@ async function monitor() {
} }
let res= followList.value.filter(item => item.StockCode===code) let res= followList.value.filter(item => item.StockCode===code)
if (res.length>0) { if (res.length>0) {
result.Sort=res[0].Sort
result.costPrice=res[0].CostPrice result.costPrice=res[0].CostPrice
result.volume=res[0].Volume result.volume=res[0].Volume
result.profit=((result["当前价格"]-result.costPrice)*100/result.costPrice).toFixed(3) result.profit=((result["当前价格"]-result.costPrice)*100/result.costPrice).toFixed(3)
@ -183,13 +203,24 @@ async function monitor() {
}else if(result.profitAmount<0){ }else if(result.profitAmount<0){
result.profitType="success" result.profitType="success"
} }
if(Math.abs(res[0].AlarmChangePercent)>0&&roundedNum>res[0].AlarmChangePercent){
SendMessage(result)
}
} }
results.value[result["股票名称"]]=result results.value[result["股票名称"]]=result
}) })
} }
} }
function onSelect(item) { function onSelect(item) {
data.code=item.split(".")[1].toLowerCase()+item.split(".")[0] console.log("onSelect",item)
if(item.indexOf("-")>0){
item=item.split("-")[1].toLowerCase()
}
if(item.indexOf(".")>0){
data.code=item.split(".")[1].toLowerCase()+item.split(".")[0]
}
} }
function search(code,name){ function search(code,name){
@ -204,6 +235,7 @@ function setStock(code,name){
formModel.value.code=code formModel.value.code=code
formModel.value.volume=res[0].Volume formModel.value.volume=res[0].Volume
formModel.value.costPrice=res[0].CostPrice formModel.value.costPrice=res[0].CostPrice
formModel.value.alarm=res[0].AlarmChangePercent
modalShow.value=true modalShow.value=true
} }
@ -221,8 +253,13 @@ function showK(code,name){
} }
function updateCostPriceAndVolumeNew(code,price,volume){ function updateCostPriceAndVolumeNew(code,price,volume,alarm){
console.log(code,price,volume) console.log(code,price,volume)
if(alarm){
SetAlarmChangePercent(alarm,code).then(result => {
//message.success(result)
})
}
SetCostPriceAndVolume(code,price,volume).then(result => { SetCostPriceAndVolume(code,price,volume).then(result => {
modalShow.value=false modalShow.value=false
message.success(result) message.success(result)
@ -247,6 +284,33 @@ function fullscreen(){
} }
data.fullscreen=!data.fullscreen data.fullscreen=!data.fullscreen
} }
function SendMessage(result){
let img='http://image.sinajs.cn/newchart/min/n/'+result["股票代码"]+'.gif'+"?t="+Date.now()
let markdown="### go-stock市场行情\n\n"+
"### "+result["股票名称"]+"("+result["股票代码"]+")\n" +
"- 当前价格: "+result["当前价格"]+" "+result.s+"\n" +
"- 最高价: "+result["今日最高价"]+" "+result.highRate+"\n" +
"- 最低价: "+result["今日最低价"]+" "+result.lowRate+"\n" +
"- 昨收价: "+result["昨日收盘价"]+"\n" +
"- 今开价: "+result["今日开盘价"]+"\n" +
"- 成本价: "+result.costPrice+" "+result.profit+"% "+result.profitAmount+" ¥\n" +
"- 成本数量: "+result.volume+"股\n" +
"- 日期: "+result["日期"]+" "+result["时间"]+"\n\n"+
"![image]("+img+")\n"
let msg='{' +
' "msgtype": "markdown",' +
' "markdown": {' +
' "title":"'+result["股票名称"]+"("+result["股票代码"]+") "+result["当前价格"]+" "+result.s+'",' +
' "text": "'+markdown+'"' +
' },' +
' "at": {' +
' "isAtAll": true' +
' }' +
' }'
SendDingDingMessage(msg,result["股票代码"])
}
</script> </script>
<template> <template>
@ -289,7 +353,7 @@ function fullscreen(){
<n-button size="tiny" type="success" @click="showFenshi(result['股票代码'],result['股票名称'])"> 分时 </n-button> <n-button size="tiny" type="success" @click="showFenshi(result['股票代码'],result['股票名称'])"> 分时 </n-button>
<n-button size="tiny" type="error" @click="showK(result['股票代码'],result['股票名称'])"> 日K </n-button> <n-button size="tiny" type="error" @click="showK(result['股票代码'],result['股票名称'])"> 日K </n-button>
<n-button size="tiny" type="warning" @click="search(result['股票代码'],result['股票名称'])"> 详情 </n-button> <n-button size="tiny" type="warning" @click="search(result['股票代码'],result['股票名称'])"> 详情 </n-button>
<!-- <n-button size="tiny" type="info" @click="SendMessage(result)"> 钉钉 </n-button>-->
</n-flex> </n-flex>
</template> </template>
</n-card > </n-card >
@ -305,8 +369,8 @@ function fullscreen(){
autocomplete: 'disabled', autocomplete: 'disabled',
}" }"
:options="options" :options="options"
placeholder="请输入股票名称或者代码" placeholder="请输入股票/指数名称或者代码"
clearable @input="getStockList" :on-select="onSelect"/> clearable @update-value="getStockList" :on-select="onSelect"/>
<n-button type="primary" @click="AddStock"> <n-button type="primary" @click="AddStock">
<n-icon :component="Add"/> &nbsp;关注该股票 <n-icon :component="Add"/> &nbsp;关注该股票
</n-button> </n-button>
@ -315,16 +379,31 @@ function fullscreen(){
</n-affix> </n-affix>
<n-modal transform-origin="center" size="small" v-model:show="modalShow" :title="formModel.name" style="width: 400px" :preset="'card'"> <n-modal transform-origin="center" size="small" v-model:show="modalShow" :title="formModel.name" style="width: 400px" :preset="'card'">
<n-form :model="formModel" :rules="{ costPrice: { required: true, message: '请输入成本'}, volume: { required: true, message: '请输入数量'} }" label-placement="left" label-width="80px"> <n-form :model="formModel" :rules="{ costPrice: { required: true, message: '请输入成本'}, volume: { required: true, message: '请输入数量'},alarm:{required: true, message: '涨跌报警值'} }" label-placement="left" label-width="80px">
<n-form-item label="成本(元)" path="costPrice"> <n-form-item label="股票成本" path="costPrice">
<n-input-number v-model:value="formModel.costPrice" min="0" placeholder="请输入股票成本" /> <n-input-number v-model:value="formModel.costPrice" min="0" placeholder="请输入股票成本" >
<template #suffix>
</template>
</n-input-number>
</n-form-item> </n-form-item>
<n-form-item label="数量(股)" path="volume"> <n-form-item label="股票数量" path="volume">
<n-input-number v-model:value="formModel.volume" min="0" placeholder="请输入股票数量" /> <n-input-number v-model:value="formModel.volume" min="0" step="100" placeholder="请输入股票数量" >
<template #suffix>
</template>
</n-input-number>
</n-form-item>
<n-form-item label="涨跌提醒" path="alarm">
<n-input-number v-model:value="formModel.alarm" min="0" placeholder="请输入涨跌报警值(%)" >
<template #suffix>
%
</template>
</n-input-number>
</n-form-item> </n-form-item>
</n-form> </n-form>
<template #footer> <template #footer>
<n-button type="primary" @click="updateCostPriceAndVolumeNew(formModel.code,formModel.costPrice,formModel.volume)">保存</n-button> <n-button type="primary" @click="updateCostPriceAndVolumeNew(formModel.code,formModel.costPrice,formModel.volume,formModel.alarm)">保存</n-button>
</template> </template>
</n-modal> </n-modal>

View File

@ -10,6 +10,10 @@ export function GetStockList(arg1:string):Promise<Array<data.StockBasic>>;
export function Greet(arg1:string):Promise<data.StockInfo>; export function Greet(arg1:string):Promise<data.StockInfo>;
export function SendDingDingMessage(arg1:string,arg2:string):Promise<string>;
export function SetAlarmChangePercent(arg1:number,arg2:string):Promise<string>;
export function SetCostPriceAndVolume(arg1:string,arg2:number,arg3:number):Promise<string>; export function SetCostPriceAndVolume(arg1:string,arg2:number,arg3:number):Promise<string>;
export function UnFollow(arg1:string):Promise<string>; export function UnFollow(arg1:string):Promise<string>;

View File

@ -18,6 +18,14 @@ export function Greet(arg1) {
return window['go']['main']['App']['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) { export function SetCostPriceAndVolume(arg1, arg2, arg3) {
return window['go']['main']['App']['SetCostPriceAndVolume'](arg1, arg2, arg3); return window['go']['main']['App']['SetCostPriceAndVolume'](arg1, arg2, arg3);
} }

View File

@ -8,6 +8,7 @@ export namespace data {
Price: number; Price: number;
PriceChange: number; PriceChange: number;
ChangePercent: number; ChangePercent: number;
AlarmChangePercent: number;
// Go type: time // Go type: time
Time: any; Time: any;
Sort: number; Sort: number;
@ -26,6 +27,7 @@ export namespace data {
this.Price = source["Price"]; this.Price = source["Price"];
this.PriceChange = source["PriceChange"]; this.PriceChange = source["PriceChange"];
this.ChangePercent = source["ChangePercent"]; this.ChangePercent = source["ChangePercent"];
this.AlarmChangePercent = source["AlarmChangePercent"];
this.Time = this.convertValues(source["Time"], null); this.Time = this.convertValues(source["Time"], null);
this.Sort = source["Sort"]; this.Sort = source["Sort"];
this.IsDel = source["IsDel"]; this.IsDel = source["IsDel"];

11
go.mod
View File

@ -5,7 +5,9 @@ go 1.21
toolchain go1.23.0 toolchain go1.23.0
require ( require (
github.com/coocood/freecache v1.2.4
github.com/duke-git/lancet/v2 v2.3.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/glebarez/sqlite v1.11.0
github.com/go-resty/resty/v2 v2.16.2 github.com/go-resty/resty/v2 v2.16.2
github.com/wailsapp/wails/v2 v2.9.2 github.com/wailsapp/wails/v2 v2.9.2
@ -19,9 +21,17 @@ require (
require ( require (
github.com/bep/debounce v1.2.1 // indirect 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/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/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-ole/go-ole v1.2.6 // 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/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // 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/leaanthony/u v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // 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/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect

29
go.sum
View File

@ -1,5 +1,9 @@
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= 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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/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 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 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 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= 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-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 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= 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 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= 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/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 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI=
github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= 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 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 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.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 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 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 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 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/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 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= 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/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.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 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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-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-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-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-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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-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-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.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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.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= 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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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= 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/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 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=

View File

@ -25,6 +25,9 @@ var assets embed.FS
//go:embed build/appicon.png //go:embed build/appicon.png
var icon []byte var icon []byte
//go:embed build/app.ico
var icon2 []byte
//go:embed build/stock_basic.json //go:embed build/stock_basic.json
var stocksBin []byte var stocksBin []byte
@ -35,11 +38,13 @@ func main() {
db.Dao.AutoMigrate(&data.StockInfo{}) db.Dao.AutoMigrate(&data.StockInfo{})
db.Dao.AutoMigrate(&data.StockBasic{}) db.Dao.AutoMigrate(&data.StockBasic{})
db.Dao.AutoMigrate(&data.FollowedStock{}) db.Dao.AutoMigrate(&data.FollowedStock{})
db.Dao.AutoMigrate(&data.IndexBasic{})
if stocksBin != nil && len(stocksBin) > 0 { if stocksBin != nil && len(stocksBin) > 0 {
go initStockData() go initStockData()
} }
go data.NewStockDataApi().GetStockBaseInfo() go data.NewStockDataApi().GetStockBaseInfo()
go data.NewStockDataApi().GetIndexBasic()
// Create an instance of the app structure // Create an instance of the app structure
app := NewApp() app := NewApp()
@ -63,9 +68,13 @@ func main() {
FileMenu.AddText("窗口还原", keys.Key("Esc"), func(callback *menu.CallbackData) { FileMenu.AddText("窗口还原", keys.Key("Esc"), func(callback *menu.CallbackData) {
runtime.WindowUnfullscreen(app.ctx) runtime.WindowUnfullscreen(app.ctx)
}) })
FileMenu.AddText("隐藏到托盘区", keys.CmdOrCtrl("h"), func(_ *menu.CallbackData) {
runtime.Hide(app.ctx)
})
FileMenu.AddText("退出", keys.CmdOrCtrl("q"), func(_ *menu.CallbackData) { FileMenu.AddText("退出", keys.CmdOrCtrl("q"), func(_ *menu.CallbackData) {
runtime.Quit(app.ctx) runtime.Quit(app.ctx)
}) })
// Create application with options // Create application with options
err := wails.Run(&options.App{ err := wails.Run(&options.App{
Title: "go-stock", Title: "go-stock",

View File

@ -1 +0,0 @@
{"request_id":"bf5b7774-d16d-43fe-9806-dff9ef37cd33","code":40203,"data":null,"msg":"抱歉您每小时最多访问该接口1次权限的具体详情访问https://tushare.pro/document/1?doc_id=108。"}