mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(cron):设置cron时,cron任务实时生效,避免重启
- 新增 AddCronTask 函数用于添加 cron 任务 - 在 App 结构中添加 cronEntrys 字典用于管理 cron 任务 ID- 优化 SetStockAICron 函数,支持更新和删除 cron 任务 - 新增 GetFollowedStockByStockCode 函数用于获取关注的股票信息 - 更新前端 API 接口,添加 AddCronTask 方法
This commit is contained in:
parent
95c3909dc9
commit
b186a17a81
34
app.go
34
app.go
@ -33,6 +33,7 @@ type App struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
cache *freecache.Cache
|
cache *freecache.Cache
|
||||||
cron *cron.Cron
|
cron *cron.Cron
|
||||||
|
cronEntrys map[string]cron.EntryID
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApp creates a new App application struct
|
// NewApp creates a new App application struct
|
||||||
@ -44,6 +45,7 @@ func NewApp() *App {
|
|||||||
return &App{
|
return &App{
|
||||||
cache: cache,
|
cache: cache,
|
||||||
cron: c,
|
cron: c,
|
||||||
|
cronEntrys: make(map[string]cron.EntryID),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,8 +174,18 @@ func (a *App) domReady(ctx context.Context) {
|
|||||||
if follow.Cron == "" {
|
if follow.Cron == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logger.SugaredLogger.Errorf("添加自动分析任务:%s cron=%s", follow.Name, follow.Cron)
|
entryID, err := a.cron.AddFunc(follow.Cron, a.AddCronTask(follow))
|
||||||
a.cron.AddFunc(follow.Cron, func() {
|
logger.SugaredLogger.Errorf("添加自动分析任务:%s cron=%s entryID:%v", follow.Name, follow.Cron, entryID)
|
||||||
|
a.cronEntrys[follow.StockCode] = entryID
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) AddCronTask(follow data.FollowedStock) func() {
|
||||||
|
return func() {
|
||||||
go runtime.EventsEmit(a.ctx, "warnMsg", "开始自动分析"+follow.Name+"_"+follow.StockCode)
|
go runtime.EventsEmit(a.ctx, "warnMsg", "开始自动分析"+follow.Name+"_"+follow.StockCode)
|
||||||
ai := data.NewDeepSeekOpenAi(a.ctx)
|
ai := data.NewDeepSeekOpenAi(a.ctx)
|
||||||
msgs := ai.NewChatStream(follow.Name, follow.StockCode, "", nil)
|
msgs := ai.NewChatStream(follow.Name, follow.StockCode, "", nil)
|
||||||
@ -196,10 +208,10 @@ func (a *App) domReady(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.NewDeepSeekOpenAi(a.ctx).SaveAIResponseResult(follow.StockCode, follow.Name, res.String(), chatId, question)
|
data.NewDeepSeekOpenAi(a.ctx).SaveAIResponseResult(follow.StockCode, follow.Name, res.String(), chatId, question)
|
||||||
})
|
go runtime.EventsEmit(a.ctx, "warnMsg", "AI分析完成:"+follow.Name+"_"+follow.StockCode)
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func refreshTelegraphList() *[]string {
|
func refreshTelegraphList() *[]string {
|
||||||
url := "https://www.cls.cn/telegraph"
|
url := "https://www.cls.cn/telegraph"
|
||||||
@ -860,8 +872,18 @@ func (a *App) AddPrompt(prompt models.Prompt) string {
|
|||||||
func (a *App) DelPrompt(id uint) string {
|
func (a *App) DelPrompt(id uint) string {
|
||||||
return data.NewPromptTemplateApi().DelPrompt(id)
|
return data.NewPromptTemplateApi().DelPrompt(id)
|
||||||
}
|
}
|
||||||
func (a *App) SetStockAICron(cron, stockCode string) {
|
func (a *App) SetStockAICron(cronText, stockCode string) {
|
||||||
data.NewStockDataApi().SetStockAICron(cron, stockCode)
|
data.NewStockDataApi().SetStockAICron(cronText, stockCode)
|
||||||
|
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
||||||
|
stockCode = strings.ToUpper(stockCode)
|
||||||
|
stockCode = strings.Replace(stockCode, "gb_", "us", 1)
|
||||||
|
stockCode = strings.Replace(stockCode, "GB_", "us", 1)
|
||||||
|
}
|
||||||
|
if entryID, exists := a.cronEntrys[stockCode]; exists {
|
||||||
|
a.cron.Remove(entryID)
|
||||||
|
}
|
||||||
|
follow := data.NewStockDataApi().GetFollowedStockByStockCode(stockCode)
|
||||||
|
a.cron.AddFunc(cronText, a.AddCronTask(follow))
|
||||||
}
|
}
|
||||||
func OnSecondInstanceLaunch(secondInstanceData options.SecondInstanceData) {
|
func OnSecondInstanceLaunch(secondInstanceData options.SecondInstanceData) {
|
||||||
notification := toast.Notification{
|
notification := toast.Notification{
|
||||||
|
@ -426,6 +426,7 @@ func (receiver StockDataApi) SetStockAICron(cron string, stockCode string) {
|
|||||||
stockCode = strings.Replace(stockCode, "GB_", "us", 1)
|
stockCode = strings.Replace(stockCode, "GB_", "us", 1)
|
||||||
}
|
}
|
||||||
db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).Update("cron", cron)
|
db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).Update("cron", cron)
|
||||||
|
|
||||||
}
|
}
|
||||||
func (receiver StockDataApi) GetFollowList() *[]FollowedStock {
|
func (receiver StockDataApi) GetFollowList() *[]FollowedStock {
|
||||||
var result *[]FollowedStock
|
var result *[]FollowedStock
|
||||||
@ -475,6 +476,12 @@ func (receiver StockDataApi) GetStockList(key string) []StockBasic {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (receiver StockDataApi) GetFollowedStockByStockCode(code string) FollowedStock {
|
||||||
|
var result FollowedStock
|
||||||
|
db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(code)).First(&result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// GB18030ToUTF8 GB18030 转换为 UTF8
|
// GB18030ToUTF8 GB18030 转换为 UTF8
|
||||||
func GB18030ToUTF8(bs []byte) string {
|
func GB18030ToUTF8(bs []byte) string {
|
||||||
reader := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GB18030.NewDecoder())
|
reader := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GB18030.NewDecoder())
|
||||||
|
4
frontend/wailsjs/go/main/App.d.ts
vendored
4
frontend/wailsjs/go/main/App.d.ts
vendored
@ -1,7 +1,9 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
import {models} from '../models';
|
|
||||||
import {data} from '../models';
|
import {data} from '../models';
|
||||||
|
import {models} from '../models';
|
||||||
|
|
||||||
|
export function AddCronTask(arg1:data.FollowedStock):Promise<any>;
|
||||||
|
|
||||||
export function AddPrompt(arg1:models.Prompt):Promise<string>;
|
export function AddPrompt(arg1:models.Prompt):Promise<string>;
|
||||||
|
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
export function AddCronTask(arg1) {
|
||||||
|
return window['go']['main']['App']['AddCronTask'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function AddPrompt(arg1) {
|
export function AddPrompt(arg1) {
|
||||||
return window['go']['main']['App']['AddPrompt'](arg1);
|
return window['go']['main']['App']['AddPrompt'](arg1);
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,61 @@ export namespace data {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export class FollowedStock {
|
||||||
|
StockCode: string;
|
||||||
|
Name: string;
|
||||||
|
Volume: number;
|
||||||
|
CostPrice: number;
|
||||||
|
Price: number;
|
||||||
|
PriceChange: number;
|
||||||
|
ChangePercent: number;
|
||||||
|
AlarmChangePercent: number;
|
||||||
|
AlarmPrice: number;
|
||||||
|
// Go type: time
|
||||||
|
Time: any;
|
||||||
|
Sort: number;
|
||||||
|
Cron: string;
|
||||||
|
IsDel: number;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new FollowedStock(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.StockCode = source["StockCode"];
|
||||||
|
this.Name = source["Name"];
|
||||||
|
this.Volume = source["Volume"];
|
||||||
|
this.CostPrice = source["CostPrice"];
|
||||||
|
this.Price = source["Price"];
|
||||||
|
this.PriceChange = source["PriceChange"];
|
||||||
|
this.ChangePercent = source["ChangePercent"];
|
||||||
|
this.AlarmChangePercent = source["AlarmChangePercent"];
|
||||||
|
this.AlarmPrice = source["AlarmPrice"];
|
||||||
|
this.Time = this.convertValues(source["Time"], null);
|
||||||
|
this.Sort = source["Sort"];
|
||||||
|
this.Cron = source["Cron"];
|
||||||
|
this.IsDel = source["IsDel"];
|
||||||
|
}
|
||||||
|
|
||||||
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
if (!a) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (a.slice && a.map) {
|
||||||
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||||
|
} else if ("object" === typeof a) {
|
||||||
|
if (asMap) {
|
||||||
|
for (const key of Object.keys(a)) {
|
||||||
|
a[key] = new classs(a[key]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return new classs(a);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Settings {
|
export class Settings {
|
||||||
ID: number;
|
ID: number;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user