mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
commit
6116e9287a
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -47,4 +47,4 @@ jobs:
|
||||
go-version: '1.24'
|
||||
build-tags: ${{ github.ref_name }}
|
||||
build-commit-message: ${{ steps.get_commit_message.outputs.commit_message }}
|
||||
node-version: '18.x'
|
||||
node-version: '20.x'
|
||||
|
23
README.md
23
README.md
@ -26,16 +26,17 @@
|
||||
|
||||
|
||||
### 💬 支持大模型/平台
|
||||
| 模型 | 状态 | 备注 |
|
||||
| --- | --- |-----------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [OpenAI](https://platform.openai.com/) | ✅ | 可接入任何 OpenAI 接口格式模型 |
|
||||
| [Ollama](https://ollama.com/) | ✅ | 本地大模型运行平台 |
|
||||
| [LMStudio](https://lmstudio.ai/) | ✅ | 本地大模型运行平台 |
|
||||
| [AnythingLLM](https://anythingllm.com/) | ✅ | 本地知识库 |
|
||||
| [DeepSeek](https://www.deepseek.com/) | ✅ | deepseek-reasoner,deepseek-chat |
|
||||
| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[硅基流动](https://cloud.siliconflow.cn/i/foufCerk),[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) |
|
||||
| 模型 | 状态 | 备注 |
|
||||
| --- | --- |---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [OpenAI](https://platform.openai.com/) | ✅ | 可接入任何 OpenAI 接口格式模型 |
|
||||
| [Ollama](https://ollama.com/) | ✅ | 本地大模型运行平台 |
|
||||
| [LMStudio](https://lmstudio.ai/) | ✅ | 本地大模型运行平台 |
|
||||
| [AnythingLLM](https://anythingllm.com/) | ✅ | 本地知识库 |
|
||||
| [DeepSeek](https://www.deepseek.com/) | ✅ | deepseek-reasoner,deepseek-chat |
|
||||
| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[硅基流动](https://cloud.siliconflow.cn/i/foufCerk),[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) ,[优云智算](https://www.compshare.cn/image-community?ytag=GPU_YY-gh_gostock) |
|
||||
|
||||
### <span style="color: #568DF4;">各位亲爱的朋友们,如果您对这个项目感兴趣,请先给我一个<i style="color: #EA2626;">star</i>吧,谢谢!</span>💕
|
||||
- 优云智算(by UCloud):万卡规模4090免费用10小时,新人注册另增50万tokens,海量热门源项目镜像一键部署,[注册链接](https://www.compshare.cn/image-community?ytag=GPU_YY-gh_gostock)
|
||||
- 经测试目前硅基流动(siliconflow)提供的deepSeek api 服务比较稳定,注册即送2000万Tokens,[注册链接](https://cloud.siliconflow.cn/i/foufCerk)
|
||||
- 火山方舟:每个模型注册即送50万tokens,[注册链接](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ)
|
||||
- Tushare大数据开放社区,免费提供各类金融数据,助力行业和量化研究(注意:Tushare只需要120积分即可,注册完成个人资料补充即可得120积分!!!),[注册链接](https://tushare.pro/register?reg=701944)
|
||||
@ -46,6 +47,8 @@
|
||||
## 🧩 重大功能开发计划
|
||||
| 功能说明 | 状态 | 备注 |
|
||||
|-----------------|----|----------------------------------------------------------------------------------------------------------|
|
||||
| 股票分析知识库 | 🚧 | 未来计划 |
|
||||
| Ai智能选股 | 🚧 | Ai智能选股功能开发中(下半年重点开发计划) |
|
||||
| ETF支持 | 🚧 | ETF数据支持 (目前可以查看净值和估值) |
|
||||
| 美股支持 | ✅ | 美股数据支持 |
|
||||
| 港股支持 | ✅ | 港股数据支持 |
|
||||
@ -54,7 +57,9 @@
|
||||
| 不再强制依赖Chrome浏览器 | ✅ | 默认使用edge浏览器抓取新闻资讯 |
|
||||
|
||||
## 👀 更新日志
|
||||
|
||||
### 2025.06.30 添加指标选股功能
|
||||
### 2025.06.27 添加财经日历和重大事件时间轴功能
|
||||
### 2025.06.25 添加热门股票、事件和话题功能
|
||||
### 2025.06.18 更新内置股票基础数据,软件内实时市场资讯信息提醒,添加行业研究功能
|
||||
### 2025.06.15 添加公司公告信息搜索/查看功能
|
||||
### 2025.06.15 添加个股研报到弹出菜单
|
||||
|
@ -31,3 +31,31 @@ func (a App) EMDictCode(code string) []any {
|
||||
func (a App) AnalyzeSentiment(text string) data.SentimentResult {
|
||||
return data.AnalyzeSentiment(text)
|
||||
}
|
||||
|
||||
func (a App) HotStock(marketType string) *[]models.HotItem {
|
||||
return data.NewMarketNewsApi().XUEQIUHotStock(100, marketType)
|
||||
}
|
||||
|
||||
func (a App) HotEvent(size int) *[]models.HotEvent {
|
||||
if size <= 0 {
|
||||
size = 10
|
||||
}
|
||||
return data.NewMarketNewsApi().HotEvent(size)
|
||||
}
|
||||
func (a App) HotTopic(size int) []any {
|
||||
if size <= 0 {
|
||||
size = 10
|
||||
}
|
||||
return data.NewMarketNewsApi().HotTopic(size)
|
||||
}
|
||||
|
||||
func (a App) InvestCalendarTimeLine(yearMonth string) []any {
|
||||
return data.NewMarketNewsApi().InvestCalendar(yearMonth)
|
||||
}
|
||||
func (a App) ClsCalendar() []any {
|
||||
return data.NewMarketNewsApi().ClsCalendar()
|
||||
}
|
||||
|
||||
func (a App) SearchStock(words string) map[string]any {
|
||||
return data.NewSearchStockApi(words).SearchStock()
|
||||
}
|
||||
|
@ -574,3 +574,130 @@ func (m MarketNewsApi) TradingViewNews() *[]models.TVNews {
|
||||
json.Unmarshal(items, TVNews)
|
||||
return TVNews
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) XUEQIUHotStock(size int, marketType string) *[]models.HotItem {
|
||||
request := resty.New().SetTimeout(time.Duration(30) * time.Second).R()
|
||||
_, err := request.
|
||||
SetHeader("Host", "xueqiu.com").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
Get("https://xueqiu.com/hq#hot")
|
||||
|
||||
//cookies := resp.Header().Get("Set-Cookie")
|
||||
//logger.SugaredLogger.Infof("cookies:%s", cookies)
|
||||
|
||||
url := fmt.Sprintf("https://stock.xueqiu.com/v5/stock/hot_stock/list.json?page=1&size=%d&_type=%s&type=%s", size, marketType, marketType)
|
||||
res := &models.XUEQIUHot{}
|
||||
_, err = request.
|
||||
SetHeader("Host", "stock.xueqiu.com").
|
||||
SetHeader("Origin", "https://xueqiu.com").
|
||||
SetHeader("Referer", "https://xueqiu.com/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
//SetHeader("Cookie", "cookiesu=871730774144180; device_id=ee75cebba8a35005c9e7baf7b7dead59; s=ch12b12pfi; Hm_lvt_1db88642e346389874251b5a1eded6e3=1746247619; xq_a_token=361dcfccb1d32a1d9b5b65f1a188b9c9ed1e687d; xqat=361dcfccb1d32a1d9b5b65f1a188b9c9ed1e687d; xq_r_token=450d1db0db9659a6af7cc9297bfa4fccf1776fae; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTc1MzgzODAwNiwiY3RtIjoxNzUxMjUxMzc2MDY3LCJjaWQiOiJkOWQwbjRBWnVwIn0.TjEtQ5WEN4ajnVjVnY3J-Qq9LjL-F0eat9Cefv_tLJLqsPhzD2y8Lc1CeIu0Ceqhlad7O_yW1tR9nb2dIjDpyOPzWKxvwSOKXLm8XMoz4LMgE2pysBCH4TsetzHsEOhBsY467q-JX3WoFuqo-dqv1FfLSondZCspjEMFdgPFt2V-2iXJY05YUwcBVUvL74mT9ZjNq0KaDeRBJk_il6UR8yibG7RMbe9xWYz5dSO_wJwWuxvnZ8u9EXC2m-TV7-QHVxFHR_5e8Fodrzg0yIcLU4wBTSoIIQDUKqngajX2W-nUAdo6fr78NNDmoswFVH7T7XMuQciMAqj9MpMCVW3Sog; u=871730774144180; ssxmod_itna=iq+h7KAImDORKYQ4Y5G=nxBKDtD7D3qCD0dGMDxeq7tDRDFqApKDHtA68oon7ziBA0+PbZ9xGN4oYxiNDAPq0iDC+Wjxs9Orw5KQb9iqP4MAn0TbNsbtU22eqbCe=S3vTv6xoDHxY=DU1GzeieDx=PD5xDTDWeDGDD3DmnsDi5YD0KDjBYpH+omDYPDEBYDaxDbDimwY4GCrDDCtc5Dw6bmzDDzznL5WWAPzWffZg3YcFgxf8GwD7y3Dla4rMhw23=cz0Efdk0A5hYDXotDvhoY1/H6neEvOt3o=Q0ruT+5RuxoRhDxCmh5tGP32xBD5G0xS2xcb4quDK0Dy2ZmY/DDWM0qmEeSEDeOCIq1fw1misCY=WAzoOtMwDzGdUjpRk5Z0xQBDI2IMw4H7qNiNBLxWiDD; ssxmod_itna2=iq+h7KAImDORKYQ4Y5G=nxBKDtD7D3qCD0dGMDxeq7tDRDFqApKDHtA68oon7ziBA0+PbZYxD3boBmiEPtDFOEPAeFmDDsuGSxf46oGKwGHd8wtUjFe+oV1lxUzutkGly=nCyCjq=UTHxMxFCr1DsFiKPuEpPVO7GrOyk5Aymnc0+11AFND7v16PvwrFQH4I72=3O1OpK7rGw+poWNCxjj=Ka5QDFWAvEzrDFQcIH=GpKpS90FAyIzGcTyck+yhQKaojn96dRqeIh=HkaFrlGnKwzO+a49=F7/c/MejoR3QM20K9IIOymrMN2bsk2TRdKFiaf4O0ut2MauiOER=iQNW2WVgDrkKzD=57r577wEx2hwkqhf8T8BDvkHZRDirC0bNK4O=G3TSkd3wYwq8bst0t9qF/e3M87NYtU2IWYWzqd=BqEfdqGq0R8wxmqLzpeGeuwSTq1OAiB87gDrozjnGkwDKRdrLz8uDjQKVlGhWk8Wd/rXQjx4pG=BNqpW/6TS1wpfxzGf5CrUhtt0j0wC5AUFo2GbX+QXPzD2guxKXrx8lZUQlwWIHyEUz+OLh0eWUkfHfM0YWXlgOejnuUa06rW9y5maDPipGms751hxKcqLq62pQty4iX3QDF6SRQd3tfEBf3CH7r2xe2qq0qdOI5Ge=GezD/Us5Z0xQBwVAZ2N/XvD0HDD").
|
||||
SetResult(res).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("XUEQIUHotStock err:%s", err.Error())
|
||||
return &[]models.HotItem{}
|
||||
}
|
||||
logger.SugaredLogger.Infof("XUEQIUHotStock:%+v", res)
|
||||
return &res.Data.Items
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) HotEvent(size int) *[]models.HotEvent {
|
||||
events := &[]models.HotEvent{}
|
||||
url := fmt.Sprintf("https://xueqiu.com/hot_event/list.json?count=%d", size)
|
||||
resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
|
||||
SetHeader("Host", "xueqiu.com").
|
||||
SetHeader("Origin", "https://xueqiu.com").
|
||||
SetHeader("Referer", "https://xueqiu.com/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
SetHeader("Cookie", "cookiesu=2617378771242871; s=c2121pp1u71; device_id=237a58584ec58d8e4d4e1040700a644f1; Hm_lvt_1db88642e346389874251b5a1eded6e3=1744100219,1744599115; xq_a_token=b7259d09435458cc3f1a963479abb270a1a016ce; xqat=b7259d09435458cc3f1a963479abb270a1a016ce; xq_r_token=28108bfa1d92ac8a46bbb57722633746218621a3; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTc1MjU0MTk4OCwiY3RtIjoxNzUwMjMwNjA2NzI0LCJjaWQiOiJkOWQwbjRBWnVwIn0.kU_fz0luJoE7nr-K4UrNUi5-mAG-vMdXtuC4mUKIppILId4UpF70LB70yunxGiNSw6tPFR3-hyLvztKAHtekCUTm3XjUl5b3tEDP-ZUVqHnWXO_5hoeMI8h-Cfx6ZGlIr5x3icvTPkT0OV5CD5A33-ZDTKhKPf-DhJ_-m7CG5GbX4MseOBeMXuLUQUiYHPKhX1QUc0GTGrCzi8Mki0z49D0LVqCSgbsx3UGfowOOyx85_cXb4OAFvIjwbs2p0o_h-ibIT0ngVkkAyEDetVvlcZ_bkardhseCB7k9BEMgH2z8ihgkVxyy3P0degLmDUruhmqn5uZOCi1pVBDvCv9lBg; u=261737877124287; ssxmod_itna=QuG=D5AKiKDIqCqGKi7G7DgmmPlSDWFqKGHDyx4YK0CDmxjKiddDUQivnb8xpnQcGyGYoYhoqEeDBubrDSxD67DK4GTm+ogiw1o3B=xedQHDgBtN=7/i1K53N+rOjquLMU=kbqYxB3DExGkqj0tPi4DxaPD5xDTDWeDGDD3DnnsDQKDRx0kL0oDIxD1D0bmHUEvh38mDYePLmOmDYPYx94Y8KoDeEgsD7HUl/vIGGEAqjLPFegXLD0HolCqr4DCid1qDm+ECfkjDn9sD0KP8fn+CRoDv=tYr4ibx+o=W+8vstf9mjGe3cXseWdBmoFrmf4DA3bFAxnAxD7vYxADaDoerDGHPoxHF+PKGPtDKmiqQGeB5qbi4eg4KDHKDe3DeG0qeEP9xVUoHDDWMYYM0ICr4FBimBDM7D0x4QOECmhul5QCN/m5/74lGm=7x9Wp7A+i7xQ7wlMD4D; ssxmod_itna2=QuG=D5AKiKDIqCqGKi7G7DgmmPlSDWFqKGHDyx4YK0CDmxjKiddDUQivnb8xpnQcGyGYoYhoqoDirSDhPmGD24GajjDuGE3m7or4DlxOSGewHl6iaus2Q62SRX5CFjCds6ltF9xy6iaUuB262UkhRA8UXST=4/b+y3kGKzlGE8T29FA008ljy9jXXC7f7m7QsK667mlUooWrofk=qGZjxtcUrN1NtuAnne1hj+rQP5UnlFkxf+o7VjmatH7u7bCDlbTt3cz6CH9Fl4vye16W/ellc8I3Q37W7ZwiLGD/zPpZcnd2nsqqo/+zRbKAmz4plzwaDqGUe7f9E+P0IFRKqpRv+buQFHBSpcbwND7Q+9XWmnjI2UwKd98jIS3gPXwxvbx4OuiyH8gZ+OEt7DgE/AY/9W4VxDZrlFWyWnC4y4/I0IpAfaGKpbPmauKbkqawqv93vSf+9HamGe0Dt2PNgT3yiEB4vQP2/DdVpcGBOjFujWoHP32OshLPYI20LRCKddwEGkKqPzPwKPc3X5zuB=w2fUdtwKsAW5kQtsl8clNwjC5uDYrxR0h9xaj0xmD+YuI3GPT7xYTalRImPj2wL2=+91a304xa4bTWtP=dLGARhb/efRi0uktaz8i8C04G0x/ZWUzqRza8GGU=FfRfvb4GZM/q2rVsl0nLvRjGeAKgocLouyXs/uwZu3YxbAx30qCbjG1A533zAxIeIgD=0VAc3ixD").
|
||||
Get(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("HotEvent err:%s", err.Error())
|
||||
return events
|
||||
}
|
||||
//logger.SugaredLogger.Infof("HotEvent:%s", resp.Body())
|
||||
respMap := map[string]any{}
|
||||
err = json.Unmarshal(resp.Body(), &respMap)
|
||||
items, err := json.Marshal(respMap["list"])
|
||||
if err != nil {
|
||||
return events
|
||||
}
|
||||
json.Unmarshal(items, events)
|
||||
return events
|
||||
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) HotTopic(size int) []any {
|
||||
url := "https://gubatopic.eastmoney.com/interface/GetData.aspx?path=newtopic/api/Topic/HomePageListRead"
|
||||
resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
|
||||
SetHeader("Host", "gubatopic.eastmoney.com").
|
||||
SetHeader("Origin", "https://gubatopic.eastmoney.com").
|
||||
SetHeader("Referer", "https://gubatopic.eastmoney.com/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
SetFormData(map[string]string{
|
||||
"param": fmt.Sprintf("ps=%d&p=1&type=0", size),
|
||||
"path": "newtopic/api/Topic/HomePageListRead",
|
||||
"env": "2",
|
||||
}).
|
||||
Post(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("HotTopic err:%s", err.Error())
|
||||
return []any{}
|
||||
}
|
||||
//logger.SugaredLogger.Infof("HotTopic:%s", resp.Body())
|
||||
respMap := map[string]any{}
|
||||
err = json.Unmarshal(resp.Body(), &respMap)
|
||||
return respMap["re"].([]any)
|
||||
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) InvestCalendar(yearMonth string) []any {
|
||||
if yearMonth == "" {
|
||||
yearMonth = time.Now().Format("2006-01")
|
||||
}
|
||||
|
||||
url := "https://app.jiuyangongshe.com/jystock-app/api/v1/timeline/list"
|
||||
resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
|
||||
SetHeader("Host", "app.jiuyangongshe.com").
|
||||
SetHeader("Origin", "https://www.jiuyangongshe.com").
|
||||
SetHeader("Referer", "https://www.jiuyangongshe.com/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("token", "1cc6380a05c652b922b3d85124c85473").
|
||||
SetHeader("platform", "3").
|
||||
SetHeader("Cookie", "SESSION=NDZkNDU2ODYtODEwYi00ZGZkLWEyY2ItNjgxYzY4ZWMzZDEy").
|
||||
SetHeader("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10)).
|
||||
SetBody(map[string]string{
|
||||
"date": yearMonth,
|
||||
"grade": "0",
|
||||
}).
|
||||
Post(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("InvestCalendar err:%s", err.Error())
|
||||
return []any{}
|
||||
}
|
||||
//logger.SugaredLogger.Infof("InvestCalendar:%s", resp.Body())
|
||||
respMap := map[string]any{}
|
||||
err = json.Unmarshal(resp.Body(), &respMap)
|
||||
return respMap["data"].([]any)
|
||||
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) ClsCalendar() []any {
|
||||
url := "https://www.cls.cn/api/calendar/web/list?app=CailianpressWeb&flag=0&os=web&sv=8.4.6&type=0&sign=4b839750dc2f6b803d1c8ca00d2b40be"
|
||||
resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
|
||||
SetHeader("Host", "www.cls.cn").
|
||||
SetHeader("Origin", "https://www.cls.cn").
|
||||
SetHeader("Referer", "https://www.cls.cn/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
Get(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("ClsCalendar err:%s", err.Error())
|
||||
return []any{}
|
||||
}
|
||||
respMap := map[string]any{}
|
||||
err = json.Unmarshal(resp.Body(), &respMap)
|
||||
return respMap["data"].([]any)
|
||||
}
|
||||
|
@ -108,3 +108,46 @@ func TestTradingViewNews(t *testing.T) {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestXUEQIUHotStock(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
res := NewMarketNewsApi().XUEQIUHotStock(50, "10")
|
||||
for _, a := range *res {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestHotEvent(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
res := NewMarketNewsApi().HotEvent(50)
|
||||
for _, a := range *res {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestHotTopic(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
res := NewMarketNewsApi().HotTopic(10)
|
||||
for _, a := range res {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestInvestCalendar(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
res := NewMarketNewsApi().InvestCalendar("2025-06")
|
||||
for _, a := range res {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClsCalendar(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
res := NewMarketNewsApi().ClsCalendar()
|
||||
for _, a := range res {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
}
|
||||
}
|
||||
|
55
backend/data/search_stock_api.go
Normal file
55
backend/data/search_stock_api.go
Normal file
@ -0,0 +1,55 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go-stock/backend/logger"
|
||||
"time"
|
||||
)
|
||||
|
||||
// @Author spark
|
||||
// @Date 2025/6/28 21:02
|
||||
// @Desc
|
||||
// -----------------------------------------------------------------------------------
|
||||
type SearchStockApi struct {
|
||||
words string
|
||||
}
|
||||
|
||||
func NewSearchStockApi(words string) *SearchStockApi {
|
||||
return &SearchStockApi{words: words}
|
||||
}
|
||||
func (s SearchStockApi) SearchStock() map[string]any {
|
||||
url := "https://np-tjxg-g.eastmoney.com/api/smart-tag/stock/v3/pw/search-code"
|
||||
resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
|
||||
SetHeader("Host", "np-tjxg-g.eastmoney.com").
|
||||
SetHeader("Origin", "https://xuangu.eastmoney.com").
|
||||
SetHeader("Referer", "https://xuangu.eastmoney.com/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(fmt.Sprintf(`{
|
||||
"keyWord": "%s",
|
||||
"pageSize": 50000,
|
||||
"pageNo": 1,
|
||||
"fingerprint": "e38b5faabf9378c8238e57219f0ebc9b",
|
||||
"gids": [],
|
||||
"matchWord": "",
|
||||
"timestamp": "1751113883290349",
|
||||
"shareToGuba": false,
|
||||
"requestId": "8xTWgCDAjvQ5lmvz5mDA3Ydk2AE4yoiJ1751113883290",
|
||||
"needCorrect": true,
|
||||
"removedConditionIdList": [],
|
||||
"xcId": "xc0af28549ab330013ed",
|
||||
"ownSelectAll": false,
|
||||
"dxInfo": [],
|
||||
"extraCondition": ""
|
||||
}`, s.words)).Post(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("SearchStock-err:%+v", err)
|
||||
return map[string]any{}
|
||||
}
|
||||
respMap := map[string]any{}
|
||||
json.Unmarshal(resp.Body(), &respMap)
|
||||
//logger.SugaredLogger.Infof("resp:%+v", respMap["data"])
|
||||
return respMap
|
||||
}
|
25
backend/data/search_stock_api_test.go
Normal file
25
backend/data/search_stock_api_test.go
Normal file
@ -0,0 +1,25 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSearchStock(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
|
||||
res := NewSearchStockApi("算力股;净利润连续3年增长").SearchStock()
|
||||
data := res["data"].(map[string]any)
|
||||
result := data["result"].(map[string]any)
|
||||
dataList := result["dataList"].([]any)
|
||||
for _, v := range dataList {
|
||||
d := v.(map[string]any)
|
||||
logger.SugaredLogger.Infof("%s:%s", d["INDUSTRY"], d["SECURITY_SHORT_NAME"])
|
||||
}
|
||||
//columns := result["columns"].([]any)
|
||||
//for _, v := range columns {
|
||||
// logger.SugaredLogger.Infof("v:%+v", v)
|
||||
//}
|
||||
|
||||
}
|
@ -400,7 +400,20 @@ func (receiver StockDataApi) Follow(stockCode string) string {
|
||||
logger.SugaredLogger.Error(err)
|
||||
return "关注失败"
|
||||
}
|
||||
if strings.HasPrefix(stockCode, "us") {
|
||||
stockCode = strings.Replace(stockCode, "us", "gb_", 1)
|
||||
}
|
||||
if strings.HasPrefix(stockCode, "US") {
|
||||
stockCode = strings.Replace(stockCode, "US", "gb_", 1)
|
||||
}
|
||||
count := int64(0)
|
||||
db.Dao.Model(&FollowedStock{}).Where("is_del = ?", 0).Count(&count)
|
||||
logger.SugaredLogger.Errorf("Follow-count %v", count)
|
||||
if count >= 63 {
|
||||
return "最多只能关注63只股票"
|
||||
}
|
||||
|
||||
stockCode = strings.ToLower(stockCode)
|
||||
maxSort := int64(0)
|
||||
db.Dao.Model(&FollowedStock{}).Raw("select max(sort) as sort from followed_stock").Scan(&maxSort)
|
||||
|
||||
@ -463,15 +476,64 @@ func (receiver StockDataApi) SetAlarmChangePercent(val, alarmPrice float64, stoc
|
||||
return "设置成功"
|
||||
}
|
||||
|
||||
func (receiver StockDataApi) SetStockSort(sort int64, stockCode string) {
|
||||
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
||||
stockCode = strings.ToLower(stockCode)
|
||||
stockCode = strings.Replace(stockCode, "gb_", "us", 1)
|
||||
func (receiver StockDataApi) SetStockSort(newSort int64, stockCode string) {
|
||||
//if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
||||
// stockCode = strings.ToLower(stockCode)
|
||||
// stockCode = strings.Replace(stockCode, "gb_", "us", 1)
|
||||
//}
|
||||
|
||||
// 获取当前排序值
|
||||
var currentStock FollowedStock
|
||||
if err := db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).First(¤tStock).Error; err != nil {
|
||||
logger.SugaredLogger.Error("找不到当前股票: ", err.Error())
|
||||
return
|
||||
}
|
||||
err := db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).Update("sort", sort).Error
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Error(err.Error())
|
||||
|
||||
oldSort := currentStock.Sort
|
||||
|
||||
// 如果排序值没有变化,直接返回
|
||||
if oldSort == newSort {
|
||||
return
|
||||
}
|
||||
// 检查新排序位置是否被占用
|
||||
var count int64
|
||||
if err := db.Dao.Model(&FollowedStock{}).Where("sort = ?", newSort).Count(&count).Error; err != nil {
|
||||
logger.SugaredLogger.Error("检查新排序位置被占用失败: ", err.Error())
|
||||
return
|
||||
}
|
||||
if count == 0 {
|
||||
// 新位置未被占用,直接更新当前记录
|
||||
if err := db.Dao.Model(&FollowedStock{}).
|
||||
Where("stock_code = ?", strings.ToLower(stockCode)).
|
||||
Update("sort", newSort).Error; err != nil {
|
||||
logger.SugaredLogger.Error("更新排序位置失败: ", err.Error())
|
||||
}
|
||||
} else {
|
||||
// 新位置已被占用,需要移动其他记录
|
||||
if newSort < oldSort {
|
||||
// 向前移动:将中间记录向后移动
|
||||
if err := db.Dao.Model(&FollowedStock{}).
|
||||
Where("sort >= ? AND sort < ?", newSort, oldSort).
|
||||
Update("sort", gorm.Expr("sort + 1")).Error; err != nil {
|
||||
logger.SugaredLogger.Error("向前排序更新失败: ", err.Error())
|
||||
}
|
||||
} else {
|
||||
// 向后移动:将中间记录向前移动
|
||||
if err := db.Dao.Model(&FollowedStock{}).
|
||||
Where("sort > ? AND sort <= ?", oldSort, newSort).
|
||||
Update("sort", gorm.Expr("sort - 1")).Error; err != nil {
|
||||
logger.SugaredLogger.Error("向后排序更新失败: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 更新目标记录的排序
|
||||
if err := db.Dao.Model(&FollowedStock{}).
|
||||
Where("stock_code = ?", strings.ToLower(stockCode)).
|
||||
Update("sort", newSort).Error; err != nil {
|
||||
logger.SugaredLogger.Error("更新股票排序失败: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
func (receiver StockDataApi) SetStockAICron(cron string, stockCode string) {
|
||||
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
||||
|
@ -317,3 +317,48 @@ type TVNews struct {
|
||||
LogoId string `json:"logo_id"`
|
||||
} `json:"provider"`
|
||||
}
|
||||
|
||||
type XUEQIUHot struct {
|
||||
Data struct {
|
||||
Items []HotItem `json:"items"`
|
||||
ItemsSize int `json:"items_size"`
|
||||
} `json:"data"`
|
||||
ErrorCode int `json:"error_code"`
|
||||
ErrorDescription string `json:"error_description"`
|
||||
}
|
||||
|
||||
type HotItem struct {
|
||||
Type int `json:"type"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
Value float64 `json:"value"`
|
||||
Increment int `json:"increment"`
|
||||
RankChange int `json:"rank_change"`
|
||||
HasExist interface{} `json:"has_exist"`
|
||||
Symbol string `json:"symbol"`
|
||||
Percent float64 `json:"percent"`
|
||||
Current float64 `json:"current"`
|
||||
Chg float64 `json:"chg"`
|
||||
Exchange string `json:"exchange"`
|
||||
StockType int `json:"stock_type"`
|
||||
SubType string `json:"sub_type"`
|
||||
Ad int `json:"ad"`
|
||||
AdId interface{} `json:"ad_id"`
|
||||
ContentId interface{} `json:"content_id"`
|
||||
Page interface{} `json:"page"`
|
||||
Model interface{} `json:"model"`
|
||||
Location interface{} `json:"location"`
|
||||
TradeSession interface{} `json:"trade_session"`
|
||||
CurrentExt interface{} `json:"current_ext"`
|
||||
PercentExt interface{} `json:"percent_ext"`
|
||||
}
|
||||
|
||||
type HotEvent struct {
|
||||
PicSize interface{} `json:"pic_size"`
|
||||
Tag string `json:"tag"`
|
||||
Id int `json:"id"`
|
||||
Pic string `json:"pic"`
|
||||
Hot int `json:"hot"`
|
||||
StatusCount int `json:"status_count"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
74
frontend/package-lock.json
generated
74
frontend/package-lock.json
generated
@ -11,7 +11,7 @@
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@vavt/cm-extension": "^1.8.0",
|
||||
"@vavt/v3-extension": "^3.0.0",
|
||||
"@vicons/ionicons5": "^0.13.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"echarts": "^5.6.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
@ -22,6 +22,14 @@
|
||||
"vue3-danmaku": "^1.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vicons/antd": "^0.13.0",
|
||||
"@vicons/carbon": "^0.13.0",
|
||||
"@vicons/fa": "^0.13.0",
|
||||
"@vicons/fluent": "^0.13.0",
|
||||
"@vicons/ionicons4": "^0.13.0",
|
||||
"@vicons/ionicons5": "^0.13.0",
|
||||
"@vicons/material": "^0.13.0",
|
||||
"@vicons/tabler": "^0.13.0",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"html-docx-js-typescript": "^0.1.5",
|
||||
"naive-ui": "^2.41.0",
|
||||
@ -1433,10 +1441,53 @@
|
||||
"md-editor-v3": ">=5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vicons/antd": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vicons/antd/-/antd-0.13.0.tgz",
|
||||
"integrity": "sha512-yrUGoUSz2BbGupk9ghQOahc04n5H3MwUDM9pVPsLh9U1uqB47oRWZvYRiZaT1JKPqgTgSE6BXcVw4i9MOF4M+g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vicons/carbon": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vicons/carbon/-/carbon-0.13.0.tgz",
|
||||
"integrity": "sha512-Z/jExyyS4gsXJc66oTqV/j98nsaiX2JlQ0IUwu9Ms3rztf8VOHEQRuX8Jey1/zbxJpFY/tU+bWvKPRFYGIvCWQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vicons/fa": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vicons/fa/-/fa-0.13.0.tgz",
|
||||
"integrity": "sha512-BFcDewcT78fSn4Y/fOgqlswbLUEW3+qJK2iJiNtgmkMzadBVpDXhNyVKsYM3V2uKPvDUrZT0JCWDWVRCiBXJZA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vicons/fluent": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vicons/fluent/-/fluent-0.13.0.tgz",
|
||||
"integrity": "sha512-bYGZsOE3qzvm3Cm43e7tybgGlr5ZUpYqtRZq0g0Tfupe8jIzLolpvQLNUt1zS8Mgt6goTbUk5YH7Fkv16jkykg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vicons/ionicons4": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vicons/ionicons4/-/ionicons4-0.13.0.tgz",
|
||||
"integrity": "sha512-5WHIl/4R5a4i9GONa+hIQWxg/WczrbsCdqxawHZvdd3drsEr+Q3yzlfS+NNRO4WS3uDW2uWLCwoW+yp5TgcKeQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vicons/ionicons5": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vicons/ionicons5/-/ionicons5-0.13.0.tgz",
|
||||
"integrity": "sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ=="
|
||||
"integrity": "sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vicons/material": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vicons/material/-/material-0.13.0.tgz",
|
||||
"integrity": "sha512-lKVxFNprM+CaBkUH3gt6VjIeiMsKQl2zARQMwTCZruQl2vRHzyeZiKeCflWS99CEfv2JzX/6y697smxlzyxcVw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vicons/tabler": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vicons/tabler/-/tabler-0.13.0.tgz",
|
||||
"integrity": "sha512-AykuhiqjszkIoAL/7knIFm6RDOBS1ZmQdJfQ+RNLEah0fVsxykUFCfMBSNZh8lOzC85EtdD1k5g/sv5GYk0Ohg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vitejs/plugin-vue": {
|
||||
"version": "5.2.1",
|
||||
@ -1667,10 +1718,10 @@
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-3.6.0.tgz",
|
||||
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
|
||||
"dev": true,
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-4.1.0.tgz",
|
||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
@ -2016,6 +2067,17 @@
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/naive-ui/node_modules/date-fns": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-3.6.0.tgz",
|
||||
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
|
@ -12,7 +12,7 @@
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@vavt/cm-extension": "^1.8.0",
|
||||
"@vavt/v3-extension": "^3.0.0",
|
||||
"@vicons/ionicons5": "^0.13.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"echarts": "^5.6.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
@ -23,6 +23,14 @@
|
||||
"vue3-danmaku": "^1.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vicons/antd": "^0.13.0",
|
||||
"@vicons/carbon": "^0.13.0",
|
||||
"@vicons/fa": "^0.13.0",
|
||||
"@vicons/fluent": "^0.13.0",
|
||||
"@vicons/ionicons4": "^0.13.0",
|
||||
"@vicons/ionicons5": "^0.13.0",
|
||||
"@vicons/material": "^0.13.0",
|
||||
"@vicons/tabler": "^0.13.0",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"html-docx-js-typescript": "^0.1.5",
|
||||
"naive-ui": "^2.41.0",
|
||||
|
@ -1 +1 @@
|
||||
b71b647d53bb771e87fac6e1372d9acf
|
||||
2d63c3a999d797889c01d6c96451b197
|
@ -14,7 +14,7 @@ import {createDiscreteApi,darkTheme,lightTheme , NIcon, NText,dateZhCN,zhCN} fro
|
||||
import {
|
||||
AlarmOutline,
|
||||
AnalyticsOutline,
|
||||
BarChartSharp, EaselSharp,
|
||||
BarChartSharp, Bonfire, BonfireOutline, EaselSharp,
|
||||
ExpandOutline, Flag,
|
||||
Flame, FlameSharp, InformationOutline,
|
||||
LogoGithub,
|
||||
@ -28,6 +28,11 @@ import {
|
||||
Wallet, WarningOutline,
|
||||
} from '@vicons/ionicons5'
|
||||
import {AnalyzeSentiment, GetConfig, GetGroupList} from "../wailsjs/go/main/App";
|
||||
import {Dragon, Fire, Gripfire} from "@vicons/fa";
|
||||
import {ReportSearch} from "@vicons/tabler";
|
||||
import {LocalFireDepartmentRound} from "@vicons/material";
|
||||
import {BoxSearch20Regular, CommentNote20Filled} from "@vicons/fluent";
|
||||
import {FireFilled, FireOutlined, NotificationFilled, StockOutlined} from "@vicons/antd";
|
||||
|
||||
|
||||
|
||||
@ -241,7 +246,7 @@ const menuOptions = ref([
|
||||
{default: () => '龙虎榜',}
|
||||
),
|
||||
key: 'market6',
|
||||
icon: renderIcon(Skull),
|
||||
icon: renderIcon(Dragon),
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
@ -262,7 +267,7 @@ const menuOptions = ref([
|
||||
{default: () => '个股研报',}
|
||||
),
|
||||
key: 'market7',
|
||||
icon: renderIcon(NewspaperSharp),
|
||||
icon: renderIcon(StockOutlined),
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
@ -283,7 +288,7 @@ const menuOptions = ref([
|
||||
{default: () => '公司公告',}
|
||||
),
|
||||
key: 'market8',
|
||||
icon: renderIcon(NewspaperSharp),
|
||||
icon: renderIcon(NotificationFilled),
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
@ -304,7 +309,49 @@ const menuOptions = ref([
|
||||
{default: () => '行业研究',}
|
||||
),
|
||||
key: 'market9',
|
||||
icon: renderIcon(NewspaperSharp),
|
||||
icon: renderIcon(ReportSearch),
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
RouterLink,
|
||||
{
|
||||
href: '#',
|
||||
to: {
|
||||
name: 'market',
|
||||
query: {
|
||||
name: "当前热门",
|
||||
}
|
||||
},
|
||||
onClick: () => {
|
||||
EventsEmit("changeMarketTab", {ID: 0, name: '当前热门'})
|
||||
},
|
||||
},
|
||||
{default: () => '当前热门',}
|
||||
),
|
||||
key: 'market10',
|
||||
icon: renderIcon(Gripfire),
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
RouterLink,
|
||||
{
|
||||
href: '#',
|
||||
to: {
|
||||
name: 'market',
|
||||
query: {
|
||||
name: "指标选股",
|
||||
}
|
||||
},
|
||||
onClick: () => {
|
||||
EventsEmit("changeMarketTab", {ID: 0, name: '指标选股'})
|
||||
},
|
||||
},
|
||||
{default: () => '指标选股',}
|
||||
),
|
||||
key: 'market11',
|
||||
icon: renderIcon(BoxSearch20Regular),
|
||||
},
|
||||
]
|
||||
},
|
||||
|
102
frontend/src/components/ClsCalendarTimeLine.vue
Normal file
102
frontend/src/components/ClsCalendarTimeLine.vue
Normal file
@ -0,0 +1,102 @@
|
||||
<script setup lang="ts">
|
||||
import {nextTick, onBeforeMount, onMounted, onUnmounted, ref} from 'vue'
|
||||
import {ClsCalendar} from "../../wailsjs/go/main/App";
|
||||
import { addMonths, format ,parse} from 'date-fns';
|
||||
import { zhCN } from 'date-fns/locale';
|
||||
|
||||
import {useMessage} from 'naive-ui'
|
||||
import {Star48Filled} from "@vicons/fluent";
|
||||
const today = new Date();
|
||||
const year = today.getFullYear();
|
||||
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
|
||||
const day = String(today.getDate()).padStart(2, '0');
|
||||
|
||||
// 常见格式:YYYY-MM-DD
|
||||
const formattedDate = `${year}-${month}-${day}`;
|
||||
const formattedYM = `${year}-${month}`;
|
||||
const list = ref([])
|
||||
const message=useMessage()
|
||||
|
||||
function goBackToday() {
|
||||
setTimeout(() => {
|
||||
nextTick(
|
||||
() => {
|
||||
const elementById = document.getElementById(formattedDate);
|
||||
if (elementById) {
|
||||
elementById.scrollIntoView({
|
||||
behavior: 'auto',
|
||||
block: 'start'
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
ClsCalendar().then(res => {
|
||||
list.value = res
|
||||
goBackToday();
|
||||
})
|
||||
})
|
||||
|
||||
function getweekday(date){
|
||||
let day=parse(date, 'yyyy-MM-dd', new Date())
|
||||
return format(day, 'EEEE', {locale: zhCN})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <n-timeline size="large" style="text-align: left">-->
|
||||
<!-- <n-timeline-item v-for="item in list" :key="item.date" :title="item.date" type="info" >-->
|
||||
<!-- <n-list>-->
|
||||
<!-- <n-list-item v-for="l in item.list" :key="l.article_id ">-->
|
||||
<!-- <n-text>{{l.title}}</n-text>-->
|
||||
<!-- </n-list-item>-->
|
||||
<!-- </n-list>-->
|
||||
<!-- </n-timeline-item>-->
|
||||
<!-- </n-timeline>-->
|
||||
|
||||
<n-list bordered style="max-height: calc(100vh - 230px);text-align: left;">
|
||||
<n-scrollbar style="max-height: calc(100vh - 230px);" >
|
||||
<n-list-item v-for="(item, index) in list" :id="item.calendar_day" :key="item.calendar_day">
|
||||
<n-thing :title="item.calendar_day +' '+item.week">
|
||||
<n-list :bordered="false" hoverable>
|
||||
<n-list-item v-for="(l,i ) in item.items" :key="l.id ">
|
||||
<n-flex justify="space-between">
|
||||
<n-text :type="item.calendar_day===formattedDate?'warning':'info'">{{i+1}}# {{l.title}}
|
||||
<n-tag v-if="l.event" size="small" round type="success">事件</n-tag>
|
||||
<n-tag v-if="l.economic" size="small" round type="error">数据</n-tag>
|
||||
</n-text>
|
||||
<n-rate v-if="l.event&&(l.event.star>0)" readonly :default-value="l.event.star">
|
||||
<n-icon :component="Star48Filled"/>
|
||||
</n-rate>
|
||||
<n-rate v-if="l.economic&&(l.economic.star>0)" readonly :default-value="l.economic.star" >
|
||||
<n-icon :component="Star48Filled"/>
|
||||
</n-rate>
|
||||
</n-flex>
|
||||
|
||||
<n-flex v-if="l.economic">
|
||||
<n-tag type="warning" :bordered="false" :size="'small'">公布:{{l.economic.actual }}</n-tag>
|
||||
<n-tag type="warning" :bordered="false" :size="'small'">预测:{{l.economic.consensus}}</n-tag>
|
||||
<n-tag type="warning" :bordered="false" :size="'small'">前值:{{l.economic.front}}</n-tag>
|
||||
</n-flex>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item v-if="list.length==0">
|
||||
<n-text type="info">没有数据</n-text>
|
||||
</n-list-item>
|
||||
<n-list-item v-else style="text-align: center;">
|
||||
<n-button-group>
|
||||
<n-button strong secondary type="warning" @click="goBackToday">回到今天</n-button>
|
||||
</n-button-group>
|
||||
</n-list-item>
|
||||
</n-scrollbar>
|
||||
</n-list>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
37
frontend/src/components/HotEvents.vue
Normal file
37
frontend/src/components/HotEvents.vue
Normal file
@ -0,0 +1,37 @@
|
||||
<script setup lang="ts">
|
||||
import {onBeforeMount, onUnmounted, ref} from 'vue'
|
||||
import {HotEvent} from "../../wailsjs/go/main/App";
|
||||
const list = ref([])
|
||||
|
||||
const task =ref()
|
||||
onBeforeMount(async () => {
|
||||
list.value = await HotEvent(50)
|
||||
task.value=setInterval(async ()=>{
|
||||
list.value = await HotEvent(50)
|
||||
}, 1000*10)
|
||||
})
|
||||
|
||||
onUnmounted(async ()=>{
|
||||
clearInterval(task.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-list bordered>
|
||||
<template #header>
|
||||
雪球热门
|
||||
</template>
|
||||
<n-list-item v-for="(item, index) in list" :key="index">
|
||||
<n-thing :title="item.tag" :description="item.content" >
|
||||
<template v-if="item.pic" #avatar>
|
||||
<n-avatar :src="item.pic" :size="60">
|
||||
</n-avatar>
|
||||
</template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
88
frontend/src/components/HotStockList.vue
Normal file
88
frontend/src/components/HotStockList.vue
Normal file
@ -0,0 +1,88 @@
|
||||
<script setup lang="ts">
|
||||
import {onBeforeMount, onUnmounted, ref} from 'vue'
|
||||
import {HotStock} from "../../wailsjs/go/main/App";
|
||||
import KLineChart from "./KLineChart.vue";
|
||||
import {ArrowBack, ArrowDown, ArrowUp} from "@vicons/ionicons5";
|
||||
|
||||
const {marketType}=defineProps(
|
||||
{
|
||||
marketType: {
|
||||
type: String,
|
||||
default: '10'
|
||||
}
|
||||
}
|
||||
)
|
||||
const task =ref()
|
||||
|
||||
const list = ref([])
|
||||
|
||||
onBeforeMount(async () => {
|
||||
list.value = await HotStock(marketType)
|
||||
task.value = setInterval(async () => {
|
||||
list.value = await HotStock(marketType)
|
||||
}, 5000)
|
||||
})
|
||||
onUnmounted(()=>{
|
||||
clearInterval(task.value)
|
||||
})
|
||||
|
||||
function getMarketCode(item) {
|
||||
if (item.exchange === 'SZ') {
|
||||
return item.code.toLowerCase()
|
||||
}
|
||||
if (item.exchange === 'SH') {
|
||||
return item.code.toLowerCase()
|
||||
}
|
||||
if (item.exchange === 'HK') {
|
||||
return (item.exchange + item.code).toLowerCase()
|
||||
}
|
||||
return ("gb_"+item.code).toLowerCase()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-table striped size="small">
|
||||
<n-thead>
|
||||
<n-tr>
|
||||
<n-th>股票名称</n-th>
|
||||
<n-th>涨跌幅</n-th>
|
||||
<n-th>当前价格</n-th>
|
||||
<n-th>热度</n-th>
|
||||
<n-th>热度变化</n-th>
|
||||
<n-th>排名变化</n-th>
|
||||
</n-tr>
|
||||
</n-thead>
|
||||
<n-tbody>
|
||||
<n-tr v-for="item in list" :key="item.code">
|
||||
<n-td><n-text type="info">
|
||||
<n-popover trigger="hover" placement="right">
|
||||
<template #trigger>
|
||||
<n-tag type="info" :bordered="false"> {{item.name}} {{item.code}}</n-tag>
|
||||
</template>
|
||||
<k-line-chart style="width: 800px" :code="getMarketCode(item)" :chart-height="500" :name="item.name" :k-days="20" :dark-theme="true"></k-line-chart>
|
||||
</n-popover>
|
||||
</n-text></n-td>
|
||||
<n-td><n-text :type="item.percent>0?'error':'success'">{{item.percent}}%</n-text></n-td>
|
||||
<n-td><n-text type="info">{{item.current}}</n-text></n-td>
|
||||
<n-td><n-text type="info">{{item.value}}</n-text></n-td>
|
||||
<n-td><n-text :type="item.increment>0?'error':'success'">
|
||||
{{item.increment}}
|
||||
<n-icon v-if="item.increment>0" :component="ArrowUp"/>
|
||||
<n-icon v-else :component="ArrowDown"/>
|
||||
</n-text></n-td>
|
||||
<n-td>
|
||||
<n-text :type="item.rank_change>0?'error':'success'">
|
||||
{{item.rank_change}}
|
||||
<n-icon v-if="item.rank_change>0" :component="ArrowUp"/>
|
||||
<n-text v-else-if="item.rank_change==0" ></n-text>
|
||||
<n-icon v-else :component="ArrowDown"/>
|
||||
</n-text>
|
||||
</n-td>
|
||||
</n-tr>
|
||||
</n-tbody>
|
||||
</n-table>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
73
frontend/src/components/HotTopics.vue
Normal file
73
frontend/src/components/HotTopics.vue
Normal file
@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import {onBeforeMount, onUnmounted, ref} from 'vue'
|
||||
import {HotTopic} from "../../wailsjs/go/main/App";
|
||||
const list = ref([])
|
||||
const task =ref()
|
||||
|
||||
onBeforeMount(async () => {
|
||||
list.value = await HotTopic(10)
|
||||
setInterval(async ()=>{
|
||||
list.value = await HotTopic(10)
|
||||
}, 1000*10)
|
||||
})
|
||||
onUnmounted(()=>{
|
||||
clearInterval(task.value)
|
||||
})
|
||||
|
||||
function openCenteredWindow(url, width, height) {
|
||||
const left = (window.screen.width - width) / 2;
|
||||
const top = (window.screen.height - height) / 2;
|
||||
|
||||
return window.open(
|
||||
url,
|
||||
'centeredWindow',
|
||||
`width=${width},height=${height},left=${left},top=${top}`
|
||||
);
|
||||
}
|
||||
function showPage(htid) {
|
||||
openCenteredWindow(`https://gubatopic.eastmoney.com/topic_v3.html?htid=${htid}`, 1000, 600)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-list bordered hoverable clickable>
|
||||
<!-- <template #header>-->
|
||||
<!-- 股吧热门-->
|
||||
<!-- </template>-->
|
||||
<n-list-item v-for="(item, index) in list" :key="index">
|
||||
<n-thing :title="item.nickname" :description="item.desc" :description-style="'font-size: 14px;'" @click="showPage(item.htid)">
|
||||
<template v-if="item.squareImg" #avatar>
|
||||
<n-avatar :src="item.squareImg" :size="60">
|
||||
</n-avatar>
|
||||
</template>
|
||||
<template v-if="item.stock_list" #footer>
|
||||
<n-flex>
|
||||
<n-tag type="info" v-for="(v, i) in item.stock_list" :bordered="false" size="small">
|
||||
{{v.name}}
|
||||
</n-tag>
|
||||
</n-flex>
|
||||
</template>
|
||||
<template v-if="item.clickNumber" #header-extra>
|
||||
<n-flex>
|
||||
<n-button secondary type="warning" size="tiny">讨论数:<n-number-animation
|
||||
show-separator
|
||||
:from="0"
|
||||
:to="item.postNumber"
|
||||
/>
|
||||
</n-button >
|
||||
<n-tag :bordered="false" type="warning" size="small">浏览量:<n-number-animation
|
||||
show-separator
|
||||
:from="0"
|
||||
:to="item.clickNumber"
|
||||
/>
|
||||
</n-tag>
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
108
frontend/src/components/InvestCalendarTimeLine.vue
Normal file
108
frontend/src/components/InvestCalendarTimeLine.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<script setup lang="ts">
|
||||
import {nextTick, onBeforeMount, onMounted, onUnmounted, ref} from 'vue'
|
||||
import {InvestCalendarTimeLine} from "../../wailsjs/go/main/App";
|
||||
import { addMonths, format ,parse} from 'date-fns';
|
||||
import { zhCN } from 'date-fns/locale';
|
||||
|
||||
import {useMessage} from 'naive-ui'
|
||||
import {Star48Filled} from "@vicons/fluent";
|
||||
const today = new Date();
|
||||
const year = today.getFullYear();
|
||||
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
|
||||
const day = String(today.getDate()).padStart(2, '0');
|
||||
|
||||
// 常见格式:YYYY-MM-DD
|
||||
const formattedDate = `${year}-${month}-${day}`;
|
||||
const formattedYM = `${year}-${month}`;
|
||||
const list = ref([])
|
||||
const message=useMessage()
|
||||
|
||||
function goBackToday() {
|
||||
setTimeout(() => {
|
||||
nextTick(
|
||||
() => {
|
||||
const elementById = document.getElementById(formattedDate);
|
||||
if (elementById) {
|
||||
elementById.scrollIntoView({
|
||||
behavior: 'auto',
|
||||
block: 'start'
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
InvestCalendarTimeLine(formattedYM).then(res => {
|
||||
list.value = res
|
||||
goBackToday();
|
||||
})
|
||||
})
|
||||
onMounted(()=>{
|
||||
|
||||
})
|
||||
function loadMore(){
|
||||
if (list.value.length>0){
|
||||
let day=parse(list.value[list.value.length-1].date, 'yyyy-MM-dd', new Date())
|
||||
let nextMonth=addMonths(day,1)
|
||||
let ym = format(nextMonth, 'yyyy-MM');
|
||||
console.log(ym)
|
||||
InvestCalendarTimeLine(ym).then(res => {
|
||||
if (res.length==0){
|
||||
message.warning("没有更多数据了")
|
||||
return
|
||||
}
|
||||
list.value.push( ...res)
|
||||
})
|
||||
}
|
||||
}
|
||||
function getweekday(date){
|
||||
let day=parse(date, 'yyyy-MM-dd', new Date())
|
||||
return format(day, 'EEEE', {locale: zhCN})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <n-timeline size="large" style="text-align: left">-->
|
||||
<!-- <n-timeline-item v-for="item in list" :key="item.date" :title="item.date" type="info" >-->
|
||||
<!-- <n-list>-->
|
||||
<!-- <n-list-item v-for="l in item.list" :key="l.article_id ">-->
|
||||
<!-- <n-text>{{l.title}}</n-text>-->
|
||||
<!-- </n-list-item>-->
|
||||
<!-- </n-list>-->
|
||||
<!-- </n-timeline-item>-->
|
||||
<!-- </n-timeline>-->
|
||||
|
||||
<n-list bordered style="max-height: calc(100vh - 230px);text-align: left;">
|
||||
<n-scrollbar style="max-height: calc(100vh - 230px);" >
|
||||
<n-list-item v-for="(item, index) in list" :id="item.date" :key="item.date">
|
||||
<n-thing :title="item.date+' '+getweekday(item.date)">
|
||||
<n-list :bordered="false" hoverable>
|
||||
<n-list-item v-for="(l,i ) in item.list" :key="l.article_id ">
|
||||
<n-flex justify="space-between">
|
||||
<n-text :type="item.date===formattedDate?'warning':'info'">{{i+1}}# {{l.title}}</n-text>
|
||||
<n-rate v-if="l.like_count>0" readonly :default-value="l.like_count" :count="l.like_count" >
|
||||
<n-icon :component="Star48Filled"/>
|
||||
</n-rate>
|
||||
</n-flex>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item v-if="list.length==0">
|
||||
<n-text type="info">没有数据</n-text>
|
||||
</n-list-item>
|
||||
<n-list-item v-else style="text-align: center;">
|
||||
<n-button-group>
|
||||
<n-button strong secondary type="info" @click="loadMore">加载更多</n-button>
|
||||
<n-button strong secondary type="warning" @click="goBackToday">回到今天</n-button>
|
||||
</n-button-group>
|
||||
</n-list-item>
|
||||
</n-scrollbar>
|
||||
</n-list>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -60,7 +60,7 @@ function handleKLine(code,name){
|
||||
////console.log("values",values)
|
||||
let option = {
|
||||
title: {
|
||||
text: name,
|
||||
text: name+" "+code,
|
||||
left: '20px',
|
||||
textStyle: {
|
||||
color: darkTheme?'#ccc':'#456'
|
||||
|
126
frontend/src/components/SelectStock.vue
Normal file
126
frontend/src/components/SelectStock.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<script setup lang="ts">
|
||||
import {h, onBeforeMount, onMounted, onUnmounted, ref} from 'vue'
|
||||
import {SearchStock} from "../../wailsjs/go/main/App";
|
||||
import {useMessage, NText, NTag} from 'naive-ui'
|
||||
const message = useMessage()
|
||||
const search = ref('科技股;换手率连续3日大于2')
|
||||
const columns = ref([])
|
||||
const dataList = ref([])
|
||||
|
||||
function Search() {
|
||||
const loading = message.loading("正在获取选股数据...", {duration: 0});
|
||||
SearchStock(search.value).then(res => {
|
||||
loading.destroy()
|
||||
//console.log(res)
|
||||
if(res.code==100){
|
||||
message.success(res.msg)
|
||||
columns.value=res.data.result.columns.filter(item=>!item.hiddenNeed&&(item.title!="市场码"&&item.title!="市场简称")).map(item=>{
|
||||
|
||||
if(item.children){
|
||||
return {
|
||||
title:item.title+(item.unit?'['+item.unit+']':''),
|
||||
key:item.key,
|
||||
resizable: true,
|
||||
minWidth:200,
|
||||
ellipsis: {
|
||||
tooltip: true
|
||||
},
|
||||
children:item.children.filter(item=>!item.hiddenNeed).map(item=>{
|
||||
return {
|
||||
title:item.dateMsg,
|
||||
key:item.key,
|
||||
minWidth:100,
|
||||
resizable: true,
|
||||
ellipsis: {
|
||||
tooltip: true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}else{
|
||||
return {
|
||||
title:item.title+(item.unit?'['+item.unit+']':''),
|
||||
key:item.key,
|
||||
resizable: true,
|
||||
minWidth:100,
|
||||
ellipsis: {
|
||||
tooltip: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
dataList.value=res.data.result.dataList
|
||||
}else {
|
||||
message.error(res.msg)
|
||||
}
|
||||
}).catch(err => {
|
||||
message.error(err)
|
||||
})
|
||||
}
|
||||
function isNumeric(value) {
|
||||
return !isNaN(parseFloat(value)) && isFinite(value);
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
Search()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-flex>
|
||||
<n-input-group>
|
||||
<n-input v-model:value="search" placeholder="请输入选股指标或者要求" />
|
||||
<n-button type="success" @click="Search">搜索A股</n-button>
|
||||
</n-input-group>
|
||||
</n-flex>
|
||||
<!-- <n-table striped size="small">-->
|
||||
<!-- <n-thead>-->
|
||||
<!-- <n-tr>-->
|
||||
<!-- <n-th v-for="item in columns">{{item.title}}</n-th>-->
|
||||
<!-- </n-tr>-->
|
||||
<!-- </n-thead>-->
|
||||
<!-- <n-tbody>-->
|
||||
<!-- <n-tr v-for="(item,index) in dataList">-->
|
||||
<!-- <n-td v-for="d in columns">{{item[d.key]}}</n-td>-->
|
||||
<!-- </n-tr>-->
|
||||
<!-- </n-tbody>-->
|
||||
<!-- </n-table>-->
|
||||
<n-data-table
|
||||
:max-height="'calc(100vh - 285px)'"
|
||||
size="small"
|
||||
:columns="columns"
|
||||
:data="dataList"
|
||||
:pagination="false"
|
||||
:scroll-x="1800"
|
||||
:render-cell="(value, rowData, column) => {
|
||||
|
||||
if(column.key=='SECURITY_CODE'||column.key=='SERIAL'){
|
||||
return h(NText, { type: 'info',border: false }, { default: () => `${value}` })
|
||||
}
|
||||
if (isNumeric(value)) {
|
||||
let type='info';
|
||||
if (Number(value)<0){
|
||||
type='success';
|
||||
}
|
||||
if(Number(value)>=0&&Number(value)<=5){
|
||||
type='warning';
|
||||
}
|
||||
if (Number(value)>5){
|
||||
type='error';
|
||||
}
|
||||
return h(NText, { type: type }, { default: () => `${value}` })
|
||||
}else{
|
||||
if(column.key=='SECURITY_SHORT_NAME'){
|
||||
return h(NTag, { type: 'info',bordered: false }, { default: () => `${value}` })
|
||||
}else{
|
||||
return h(NText, { type: 'info' }, { default: () => `${value}` })
|
||||
}
|
||||
}
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -135,6 +135,7 @@ EventsOn("updateVersion",async (msg) => {
|
||||
</p>
|
||||
<p>
|
||||
感谢以下开发者:
|
||||
<a href="https://github.com/CodeNoobLH" target="_blank">浓睡不消残酒</a><n-divider vertical />
|
||||
<a href="https://github.com/gnim2600" target="_blank">@gnim2600</a><n-divider vertical />
|
||||
<a href="https://github.com/XXXiaohuayanGGG" target="_blank">@XXXiaohuayanGGG</a><n-divider vertical />
|
||||
<a href="https://github.com/2lovecode" target="_blank">@2lovecode</a><n-divider vertical />
|
||||
|
@ -26,6 +26,12 @@ import StockResearchReportList from "./StockResearchReportList.vue";
|
||||
import StockNoticeList from "./StockNoticeList.vue";
|
||||
import LongTigerRankList from "./LongTigerRankList.vue";
|
||||
import IndustryResearchReportList from "./IndustryResearchReportList.vue";
|
||||
import HotStockList from "./HotStockList.vue";
|
||||
import HotEvents from "./HotEvents.vue";
|
||||
import HotTopics from "./HotTopics.vue";
|
||||
import InvestCalendarTimeLine from "./InvestCalendarTimeLine.vue";
|
||||
import ClsCalendarTimeLine from "./ClsCalendarTimeLine.vue";
|
||||
import SelectStock from "./SelectStock.vue";
|
||||
|
||||
const route = useRoute()
|
||||
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
|
||||
@ -557,8 +563,41 @@ function ReFlesh(source) {
|
||||
<n-tab-pane name="行业研究" tab="行业研究 ">
|
||||
<IndustryResearchReportList/>
|
||||
</n-tab-pane>
|
||||
|
||||
|
||||
<n-tab-pane name="当前热门" tab="当前热门">
|
||||
<n-tabs type="card" animated>
|
||||
<n-tab-pane name="全球" tab="全球">
|
||||
<HotStockList :market-type="'10'"/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="沪深" tab="沪深">
|
||||
<HotStockList :market-type="'12'"/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="港股" tab="港股">
|
||||
<HotStockList :market-type="'13'"/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="美股" tab="美股">
|
||||
<HotStockList :market-type="'11'"/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="热门话题" tab="热门话题">
|
||||
<n-grid :cols="1" :y-gap="10">
|
||||
<n-grid-item>
|
||||
<HotTopics/>
|
||||
</n-grid-item>
|
||||
<!-- <n-grid-item>-->
|
||||
<!-- <HotEvents/>-->
|
||||
<!-- </n-grid-item>-->
|
||||
</n-grid>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="重大事件时间轴" tab="重大事件时间轴">
|
||||
<InvestCalendarTimeLine />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="财经日历" tab="财经日历">
|
||||
<ClsCalendarTimeLine />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="指标选股" tab="指标选股">
|
||||
<select-stock />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
<n-modal transform-origin="center" v-model:show="summaryModal" preset="card" style="width: 800px;"
|
||||
|
File diff suppressed because it is too large
Load Diff
12
frontend/wailsjs/go/main/App.d.ts
vendored
12
frontend/wailsjs/go/main/App.d.ts
vendored
@ -15,6 +15,8 @@ export function AnalyzeSentiment(arg1:string):Promise<data.SentimentResult>;
|
||||
|
||||
export function CheckUpdate():Promise<void>;
|
||||
|
||||
export function ClsCalendar():Promise<Array<any>>;
|
||||
|
||||
export function DelPrompt(arg1:number):Promise<string>;
|
||||
|
||||
export function EMDictCode(arg1:string):Promise<Array<any>>;
|
||||
@ -65,8 +67,16 @@ export function GlobalStockIndexes():Promise<Record<string, any>>;
|
||||
|
||||
export function Greet(arg1:string):Promise<data.StockInfo>;
|
||||
|
||||
export function HotEvent(arg1:number):Promise<any>;
|
||||
|
||||
export function HotStock(arg1:string):Promise<any>;
|
||||
|
||||
export function HotTopic(arg1:number):Promise<Array<any>>;
|
||||
|
||||
export function IndustryResearchReport(arg1:string):Promise<Array<any>>;
|
||||
|
||||
export function InvestCalendarTimeLine(arg1:string):Promise<Array<any>>;
|
||||
|
||||
export function LongTigerRank(arg1:string):Promise<any>;
|
||||
|
||||
export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise<void>;
|
||||
@ -83,6 +93,8 @@ export function SaveAIResponseResult(arg1:string,arg2:string,arg3:string,arg4:st
|
||||
|
||||
export function SaveAsMarkdown(arg1:string,arg2:string):Promise<string>;
|
||||
|
||||
export function SearchStock(arg1:string):Promise<Record<string, any>>;
|
||||
|
||||
export function SendDingDingMessage(arg1:string,arg2:string):Promise<string>;
|
||||
|
||||
export function SendDingDingMessageByType(arg1:string,arg2:string,arg3:number):Promise<string>;
|
||||
|
@ -26,6 +26,10 @@ export function CheckUpdate() {
|
||||
return window['go']['main']['App']['CheckUpdate']();
|
||||
}
|
||||
|
||||
export function ClsCalendar() {
|
||||
return window['go']['main']['App']['ClsCalendar']();
|
||||
}
|
||||
|
||||
export function DelPrompt(arg1) {
|
||||
return window['go']['main']['App']['DelPrompt'](arg1);
|
||||
}
|
||||
@ -126,10 +130,26 @@ export function Greet(arg1) {
|
||||
return window['go']['main']['App']['Greet'](arg1);
|
||||
}
|
||||
|
||||
export function HotEvent(arg1) {
|
||||
return window['go']['main']['App']['HotEvent'](arg1);
|
||||
}
|
||||
|
||||
export function HotStock(arg1) {
|
||||
return window['go']['main']['App']['HotStock'](arg1);
|
||||
}
|
||||
|
||||
export function HotTopic(arg1) {
|
||||
return window['go']['main']['App']['HotTopic'](arg1);
|
||||
}
|
||||
|
||||
export function IndustryResearchReport(arg1) {
|
||||
return window['go']['main']['App']['IndustryResearchReport'](arg1);
|
||||
}
|
||||
|
||||
export function InvestCalendarTimeLine(arg1) {
|
||||
return window['go']['main']['App']['InvestCalendarTimeLine'](arg1);
|
||||
}
|
||||
|
||||
export function LongTigerRank(arg1) {
|
||||
return window['go']['main']['App']['LongTigerRank'](arg1);
|
||||
}
|
||||
@ -162,6 +182,10 @@ export function SaveAsMarkdown(arg1, arg2) {
|
||||
return window['go']['main']['App']['SaveAsMarkdown'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function SearchStock(arg1) {
|
||||
return window['go']['main']['App']['SearchStock'](arg1);
|
||||
}
|
||||
|
||||
export function SendDingDingMessage(arg1, arg2) {
|
||||
return window['go']['main']['App']['SendDingDingMessage'](arg1, arg2);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user