diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 8bfb5de..dcdbe05 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -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'
diff --git a/README.md b/README.md
index e8511ef..647c819 100644
--- a/README.md
+++ b/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) |
### 各位亲爱的朋友们,如果您对这个项目感兴趣,请先给我一个star吧,谢谢!💕
+- 优云智算(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 添加个股研报到弹出菜单
diff --git a/app_common.go b/app_common.go
index a73a611..a82ed4b 100644
--- a/app_common.go
+++ b/app_common.go
@@ -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()
+}
diff --git a/backend/data/market_news_api.go b/backend/data/market_news_api.go
index d1e5938..904afb3 100644
--- a/backend/data/market_news_api.go
+++ b/backend/data/market_news_api.go
@@ -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)
+}
diff --git a/backend/data/market_news_api_test.go b/backend/data/market_news_api_test.go
index 01d489b..9f24c16 100644
--- a/backend/data/market_news_api_test.go
+++ b/backend/data/market_news_api_test.go
@@ -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)
+ }
+}
diff --git a/backend/data/search_stock_api.go b/backend/data/search_stock_api.go
new file mode 100644
index 0000000..cea7d58
--- /dev/null
+++ b/backend/data/search_stock_api.go
@@ -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
+}
diff --git a/backend/data/search_stock_api_test.go b/backend/data/search_stock_api_test.go
new file mode 100644
index 0000000..4ca5646
--- /dev/null
+++ b/backend/data/search_stock_api_test.go
@@ -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)
+ //}
+
+}
diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go
index 8b178e3..f88b590 100644
--- a/backend/data/stock_data_api.go
+++ b/backend/data/stock_data_api.go
@@ -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_"}) {
diff --git a/backend/models/models.go b/backend/models/models.go
index f513055..10d237b 100644
--- a/backend/models/models.go
+++ b/backend/models/models.go
@@ -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"`
+}
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index f53e553..abf5ea7 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -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",
diff --git a/frontend/package.json b/frontend/package.json
index 64919e4..ebc6914 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -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",
diff --git a/frontend/package.json.md5 b/frontend/package.json.md5
index 3f00715..fce852e 100644
--- a/frontend/package.json.md5
+++ b/frontend/package.json.md5
@@ -1 +1 @@
-b71b647d53bb771e87fac6e1372d9acf
\ No newline at end of file
+2d63c3a999d797889c01d6c96451b197
\ No newline at end of file
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 930966c..f4a78ab 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -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),
},
]
},
diff --git a/frontend/src/components/ClsCalendarTimeLine.vue b/frontend/src/components/ClsCalendarTimeLine.vue
new file mode 100644
index 0000000..c823298
--- /dev/null
+++ b/frontend/src/components/ClsCalendarTimeLine.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{i+1}}# {{l.title}}
+ 事件
+ 数据
+
+
+
+
+
+
+
+
+
+
+ 公布:{{l.economic.actual }}
+ 预测:{{l.economic.consensus}}
+ 前值:{{l.economic.front}}
+
+
+
+
+
+
+ 没有数据
+
+
+
+ 回到今天
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/HotEvents.vue b/frontend/src/components/HotEvents.vue
new file mode 100644
index 0000000..8571f3f
--- /dev/null
+++ b/frontend/src/components/HotEvents.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+ 雪球热门
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/HotStockList.vue b/frontend/src/components/HotStockList.vue
new file mode 100644
index 0000000..9846deb
--- /dev/null
+++ b/frontend/src/components/HotStockList.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+ 股票名称
+ 涨跌幅
+ 当前价格
+ 热度
+ 热度变化
+ 排名变化
+
+
+
+
+
+
+
+ {{item.name}} {{item.code}}
+
+
+
+
+ {{item.percent}}%
+ {{item.current}}
+ {{item.value}}
+
+ {{item.increment}}
+
+
+
+
+
+ {{item.rank_change}}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/HotTopics.vue b/frontend/src/components/HotTopics.vue
new file mode 100644
index 0000000..e203788
--- /dev/null
+++ b/frontend/src/components/HotTopics.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{v.name}}
+
+
+
+
+
+ 讨论数:
+
+ 浏览量:
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/InvestCalendarTimeLine.vue b/frontend/src/components/InvestCalendarTimeLine.vue
new file mode 100644
index 0000000..54d8b3d
--- /dev/null
+++ b/frontend/src/components/InvestCalendarTimeLine.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{i+1}}# {{l.title}}
+
+
+
+
+
+
+
+
+
+ 没有数据
+
+
+
+ 加载更多
+ 回到今天
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/KLineChart.vue b/frontend/src/components/KLineChart.vue
index 5791430..e1889c1 100644
--- a/frontend/src/components/KLineChart.vue
+++ b/frontend/src/components/KLineChart.vue
@@ -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'
diff --git a/frontend/src/components/SelectStock.vue b/frontend/src/components/SelectStock.vue
new file mode 100644
index 0000000..af17d2d
--- /dev/null
+++ b/frontend/src/components/SelectStock.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+ 搜索A股
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/about.vue b/frontend/src/components/about.vue
index 399760d..a40f660 100644
--- a/frontend/src/components/about.vue
+++ b/frontend/src/components/about.vue
@@ -135,6 +135,7 @@ EventsOn("updateVersion",async (msg) => {
感谢以下开发者:
+ 浓睡不消残酒
@gnim2600
@XXXiaohuayanGGG
@2lovecode
diff --git a/frontend/src/components/market.vue b/frontend/src/components/market.vue
index 7944673..44eb20c 100644
--- a/frontend/src/components/market.vue
+++ b/frontend/src/components/market.vue
@@ -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) {
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{
//console.log(`Export progress: ${progress.ratio * 100}%`);
};
-const enableEditor= ref(false)
+const enableEditor = ref(false)
const mdPreviewRef = ref(null)
-const mdEditorRef = ref(null)
+const mdEditorRef = ref(null)
const tipsRef = ref(null)
const message = useMessage()
const notify = useNotification()
-const stocks=ref([])
-const results=ref({})
-const stockList=ref([])
-const followList=ref([])
-const groupList=ref([])
-const options=ref([])
+const stocks = ref([])
+const results = ref({})
+const stockList = ref([])
+const followList = ref([])
+const groupList = ref([])
+const options = ref([])
const modalShow = ref(false)
const modalShow2 = ref(false)
const modalShow3 = ref(false)
@@ -107,85 +107,82 @@ const formModel = ref({
costPrice: 0.000,
volume: 0,
alarm: 0,
- alarmPrice:0,
- sort:999,
- cron:"",
+ alarmPrice: 0,
+ sort: 999,
+ cron: "",
})
-const promptTemplates=ref([])
-const sysPromptOptions=ref([])
-const userPromptOptions=ref([])
+const promptTemplates = ref([])
+const sysPromptOptions = ref([])
+const userPromptOptions = ref([])
const data = reactive({
- modelName:"",
+ modelName: "",
chatId: "",
- question:"",
- sysPromptId:null,
+ question: "",
+ sysPromptId: null,
name: "",
code: "",
- fenshiURL:"",
- kURL:"",
+ fenshiURL: "",
+ kURL: "",
resultText: "Please enter your name below 👇",
fullscreen: false,
airesult: "",
openAiEnable: false,
loading: true,
enableDanmu: false,
- darkTheme:false,
- changePercent:0
+ darkTheme: false,
+ changePercent: 0
})
-const feishiInterval= ref(null)
+const feishiInterval = ref(null)
-const currentGroupId=ref(0)
+const currentGroupId = ref(0)
-
-const theme=computed(() => {
+const theme = computed(() => {
return data.darkTheme ? 'dark' : 'light'
})
-const danmakuColor = computed(()=> {
+const danmakuColor = computed(() => {
return data.darkTheme ? 'color:#fff' : 'color:#000'
})
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
const sortedResults = computed(() => {
- ////console.log("computed",sortedResults.value)
- const sortedKeys =keys(results.value).sort();
- ////console.log("sortedKeys",sortedKeys)
+ const sortedKeys = keys(results.value).sort();
const sortedObject = {};
sortedKeys.forEach(key => {
- sortedObject[key] = results.value[key];
+ sortedObject[key] = results.value[key];
});
return sortedObject
});
-const groupResults=computed(() => {
- const group={}
- for (const key in sortedResults.value) {
- if(stocks.value.includes(sortedResults.value[key]['股票代码'])){
- group[key]=sortedResults.value[key]
+const groupResults = computed(() => {
+ const group = {}
+ for (const key in sortedResults.value) {
+ if (stocks.value.includes(sortedResults.value[key]['股票代码'])) {
+ group[key] = sortedResults.value[key]
}
}
return group
})
-const showPopover=ref(false)
+const showPopover = ref(false)
-onBeforeMount(()=>{
+onBeforeMount(() => {
GetGroupList().then(result => {
- groupList.value=result
- if(route.query.groupId){
- message.success("切换分组:"+route.query.groupName)
- currentGroupId.value=Number(route.query.groupId)
+ groupList.value = result
+ if (route.query.groupId) {
+ message.success("切换分组:" + route.query.groupName)
+ currentGroupId.value = Number(route.query.groupId)
//console.log("route.params",route.query)
}
})
GetStockList("").then(result => {
stockList.value = result
- options.value=result.map(item => {
+ options.value = result.map(item => {
return {
- label: item.name+" - "+item.ts_code,
+ label: item.name + " - " + item.ts_code,
value: item.ts_code
}
})
@@ -201,11 +198,11 @@ onBeforeMount(()=>{
data.darkTheme = true
}
})
- GetPromptTemplates("","").then(res=>{
- promptTemplates.value=res
+ GetPromptTemplates("", "").then(res => {
+ promptTemplates.value = res
- sysPromptOptions.value=promptTemplates.value.filter(item => item.type === '模型系统Prompt')
- userPromptOptions.value=promptTemplates.value.filter(item => item.type === '模型用户Prompt')
+ sysPromptOptions.value = promptTemplates.value.filter(item => item.type === '模型系统Prompt')
+ userPromptOptions.value = promptTemplates.value.filter(item => item.type === '模型用户Prompt')
//console.log("userPromptOptions",userPromptOptions.value)
//console.log("sysPromptOptions",sysPromptOptions.value)
@@ -215,24 +212,15 @@ onBeforeMount(()=>{
onMounted(() => {
message.loading("Loading...")
- // //console.log(`the component is now mounted.`)
-
- // ticker.value=setInterval(() => {
- // if(isTradingTime()){
- // //monitor()
- // //data.fenshiURL='http://image.sinajs.cn/newchart/min/n/'+data.code+'.gif'+"?t="+Date.now()
- // }
- // }, 3500)
GetFollowList(currentGroupId.value).then(result => {
- followList.value = result
+ followList.value = result
for (const followedStock of result) {
- if(followedStock.StockCode.startsWith("us")){
- followedStock.StockCode="gb_"+ followedStock.StockCode.replace("us", "").toLowerCase()
+ if (followedStock.StockCode.startsWith("us")) {
+ followedStock.StockCode = "gb_" + followedStock.StockCode.replace("us", "").toLowerCase()
}
if (!stocks.value.includes(followedStock.StockCode)) {
- ////console.log("followList",followedStock.StockCode)
stocks.value.push(followedStock.StockCode)
}
}
@@ -253,7 +241,7 @@ onMounted(() => {
};
ws.value.onmessage = (event) => {
- if(data.enableDanmu){
+ if (data.enableDanmu) {
danmus.value.push(event.data);
}
};
@@ -268,7 +256,7 @@ onMounted(() => {
})
onBeforeUnmount(() => {
- // //console.log(`the component is now unmounted.`)
+ // //console.log(`the component is now unmounted.`)
//clearInterval(ticker.value)
ws.value.close()
message.destroyAll()
@@ -286,80 +274,69 @@ onBeforeUnmount(() => {
EventsOff("loadingDone")
})
-EventsOn("loadingDone",(data)=>{
+EventsOn("loadingDone", (data) => {
message.loading("刷新股票基础数据...")
GetStockList("").then(result => {
stockList.value = result
- options.value=result.map(item => {
+ options.value = result.map(item => {
return {
- label: item.name+" - "+item.ts_code,
+ label: item.name + " - " + item.ts_code,
value: item.ts_code
}
})
})
})
-EventsOn("refresh",(data)=>{
+EventsOn("refresh", (data) => {
message.success(data)
})
-EventsOn("showSearch",(data)=>{
+EventsOn("showSearch", (data) => {
addBTN.value = data === 1;
})
-EventsOn("stock_price",(data)=>{
+EventsOn("stock_price", (data) => {
updateData(data)
})
-EventsOn("refreshFollowList",(data)=>{
+EventsOn("refreshFollowList", (data) => {
WindowReload()
- // message.loading("refresh...")
- // GetFollowList().then(result => {
- // followList.value = result
- // for (const followedStock of result) {
- // if (!stocks.value.includes(followedStock.StockCode)) {
- // stocks.value.push(followedStock.StockCode)
- // }
- // }
- // monitor()
- // message.destroyAll
- // })
})
-EventsOn("newChatStream",async (msg) => {
+EventsOn("newChatStream", async (msg) => {
////console.log("newChatStream:->",data.airesult)
data.loading = false
////console.log(msg)
if (msg === "DONE") {
- SaveAIResponseResult(data.code, data.name, data.airesult, data.chatId,data.question)
+ SaveAIResponseResult(data.code, data.name, data.airesult, data.chatId, data.question)
message.info("AI分析完成!")
message.destroyAll()
} else {
- if(msg.chatId){
- data.chatId = msg.chatId
- }
- if(msg.question){
- data.question = msg.question
- }
- if(msg.content){
- data.airesult = data.airesult + msg.content
- }
- if(msg.extraContent){
- data.airesult = data.airesult + msg.extraContent
- }
+ if (msg.chatId) {
+ data.chatId = msg.chatId
+ }
+ if (msg.question) {
+ data.question = msg.question
+ }
+ if (msg.content) {
+ data.airesult = data.airesult + msg.content
+ }
+ if (msg.extraContent) {
+ data.airesult = data.airesult + msg.extraContent
+ }
}
})
-EventsOn("changeTab" ,async (msg) => {
+EventsOn("changeTab", async (msg) => {
//console.log("changeTab",msg)
- currentGroupId.value=msg.ID
+ currentGroupId.value = msg.ID
updateTab(currentGroupId.value)
})
-EventsOn("updateVersion",async (msg) => {
+EventsOn("updateVersion", async (msg) => {
const githubTimeStr = msg.published_at;
// 创建一个 Date 对象
const utcDate = new Date(githubTimeStr);
@@ -392,10 +369,10 @@ EventsOn("updateVersion",async (msg) => {
'text-align': 'left',
'font-size': '14px',
}
- }, { default: () => msg.commit?.message })
+ }, {default: () => msg.commit?.message})
},
duration: 5000,
- meta: "发布时间:"+formattedDate,
+ meta: "发布时间:" + formattedDate,
action: () => {
return h(NButton, {
type: 'primary',
@@ -403,12 +380,12 @@ EventsOn("updateVersion",async (msg) => {
onClick: () => {
window.open(msg.html_url)
}
- }, { default: () => '查看' })
+ }, {default: () => '查看'})
}
})
})
-EventsOn("warnMsg",async (msg) => {
+EventsOn("warnMsg", async (msg) => {
notify.error({
avatar: () =>
h(NAvatar, {
@@ -424,7 +401,7 @@ EventsOn("warnMsg",async (msg) => {
'text-align': 'left',
'font-size': '14px',
}
- }, { default: () => msg })
+ }, {default: () => msg})
},
})
})
@@ -449,34 +426,36 @@ function isTradingTime() {
return false;
}
-function AddStock(){
+function AddStock() {
if (!data?.code) {
message.error("请输入有效股票代码");
return;
}
if (!stocks.value.includes(data.code)) {
- Follow(data.code).then(result => {
- if(result==="关注成功"){
- stocks.value.push(data.code)
- message.success(result)
- GetFollowList(currentGroupId.value).then(result => {
- followList.value = result
- })
- monitor();
- }else{
- message.error(result)
+ Follow(data.code).then(result => {
+ if (result === "关注成功") {
+ if (data.code.startsWith("us")) {
+ data.code= "gb_" + data.code.replace("us", "").toLowerCase()
}
- })
- }else{
+ stocks.value.push(data.code)
+ message.success(result)
+ GetFollowList(currentGroupId.value).then(result => {
+ followList.value = result
+ })
+ monitor();
+ } else {
+ message.error(result)
+ }
+ })
+ } else {
message.error("已经关注了")
}
}
-
-function removeMonitor(code,name,key) {
+function removeMonitor(code, name, key) {
//console.log("removeMonitor",name,code,key)
- stocks.value.splice(stocks.value.indexOf(code),1)
+ stocks.value.splice(stocks.value.indexOf(code), 1)
//console.log("removeMonitor-key",key)
//console.log("removeMonitor-v",results.value[key])
@@ -489,61 +468,58 @@ function removeMonitor(code,name,key) {
}
-function SendDanmu(){
+function SendDanmu() {
//danmus.value.push(data.name)
//console.log("SendDanmu",data.name)
//console.log("SendDanmu-readyState", ws.value.readyState)
ws.value.send(data.name)
}
-function getStockList(value){
+function getStockList(value) {
-
- // //console.log("getStockList",value)
+ // //console.log("getStockList",value)
let result;
- result=stockList.value.filter(item => item.name.includes(value)||item.ts_code.includes(value))
- options.value=result.map(item => {
+ result = stockList.value.filter(item => item.name.includes(value) || item.ts_code.includes(value))
+ options.value = result.map(item => {
return {
- label: item.name+" - "+item.ts_code,
+ label: item.name + " - " + item.ts_code,
value: item.ts_code
}
})
- if(value&&value.indexOf("-")<=0){
- data.code=value
+ if (value && value.indexOf("-") <= 0) {
+ data.code = value
}
//console.log("getStockList-options",data.code)
- if(data.code){
- let findId=data.code
- if(findId.startsWith("us")){
- findId="gb_"+ findId.replace("us", "").toLowerCase()
+ if (data.code) {
+ let findId = data.code
+ if (findId.startsWith("us")) {
+ findId = "gb_" + findId.replace("us", "").toLowerCase()
}
blinkBorder(findId)
}
-
-
}
-function blinkBorder(findId){
+function blinkBorder(findId) {
// 获取要滚动到的元素
let element = document.getElementById(findId);
//console.log("blinkBorder",findId,element)
if (element) {
// 滚动到该元素
- element.scrollIntoView({ behavior: 'smooth'});
- const pelement = document.getElementById(findId +'_gi');
- if(pelement){
+ element.scrollIntoView({behavior: 'smooth'});
+ const pelement = document.getElementById(findId + '_gi');
+ if (pelement) {
// 添加闪烁效果
pelement.classList.add('blink-border');
// 3秒后移除闪烁效果
setTimeout(() => {
pelement.classList.remove('blink-border');
- }, 1000*5);
- }else{
+ }, 1000 * 5);
+ } else {
console.error(`Element with ID ${findId}_gi not found`);
}
}
@@ -552,57 +528,60 @@ function blinkBorder(findId){
async function updateData(result) {
////console.log("stock_price",result['日期'],result['时间'],result['股票代码'],result['股票名称'],result['当前价格'],result['盘前盘后'])
- if(result["当前价格"]<=0){
- result["当前价格"]=result["卖一报价"]
+ if (result["当前价格"] <= 0) {
+ result["当前价格"] = result["卖一报价"]
}
- if (result.changePercent>0) {
- result.type="error"
- result.color="#E88080"
- }else if (result.changePercent<0) {
- result.type="success"
- result.color="#63E2B7"
- }else {
- result.type="default"
- result.color="#FFFFFF"
+ if (result.changePercent > 0) {
+ result.type = "error"
+ result.color = "#E88080"
+ } else if (result.changePercent < 0) {
+ result.type = "success"
+ result.color = "#63E2B7"
+ } else {
+ result.type = "default"
+ result.color = "#FFFFFF"
}
- if(result.profitAmount>0){
- result.profitType="error"
- }else if(result.profitAmount<0){
- result.profitType="success"
- }
- if(result["当前价格"]){
- if(result.alarmChangePercent>0&&Math.abs(result.changePercent)>=result.alarmChangePercent){
- SendMessage(result,1)
- }
-
- if(result.alarmPrice>0&&result["当前价格"]>=result.alarmPrice){
- SendMessage(result,2)
- }
-
- if(result.costPrice>0&&result["当前价格"]>=result.costPrice){
- SendMessage(result,3)
- }
+ if (result.profitAmount > 0) {
+ result.profitType = "error"
+ } else if (result.profitAmount < 0) {
+ result.profitType = "success"
+ }
+ if (result["当前价格"]) {
+ if (result.alarmChangePercent > 0 && Math.abs(result.changePercent) >= result.alarmChangePercent) {
+ SendMessage(result, 1)
}
- //result.key=result.sort
- result.key=GetSortKey(result.sort,result["股票代码"])
- results.value[GetSortKey(result.sort,result["股票代码"])]=result
- if(!stocks.value.includes(result["股票代码"])) {
+ if (result.alarmPrice > 0 && result["当前价格"] >= result.alarmPrice) {
+ SendMessage(result, 2)
+ }
+
+ if (result.costPrice > 0 && result["当前价格"] >= result.costPrice) {
+ SendMessage(result, 3)
+ }
+ }
+
+ // result.key=result.sort
+ results.value = Object.fromEntries(
+ Object.entries(results.value).filter(
+ ([key]) => !key.includes(result["股票代码"])
+ ));
+
+ result.key = GetSortKey(result.sort, result["股票代码"])
+ results.value[result.key] = result
+ if (!stocks.value.includes(result["股票代码"])) {
delete results.value[result.key]
}
-
- ////console.log("updateData",result)
}
async function monitor() {
- if(stocks.value&&stocks.value.length===0){
- showPopover.value=true
+ if (stocks.value && stocks.value.length === 0) {
+ showPopover.value = true
}
for (let code of stocks.value) {
- // //console.log(code)
+
Greet(code).then(result => {
updateData(result)
})
@@ -610,51 +589,67 @@ async function monitor() {
}
-function GetSortKey(sort,code){
- let sortKey= padStart(sort,8,'0')+"_"+code
- ////console.log("GetSortKey:",sortKey)
+function GetSortKey(sort, code) {
+ let sortKey = padStart(sort, 8, '0') + "_" + code
return sortKey
}
function onSelect(item) {
////console.log("onSelect",item)
- if(item.indexOf("-")>0){
- item=item.split("-")[1].toLowerCase()
+ if (item.indexOf("-") > 0) {
+ item = item.split("-")[1].toLowerCase()
}
- if(item.indexOf(".")>0){
- data.code=item.split(".")[1].toLowerCase()+item.split(".")[0]
+ if (item.indexOf(".") > 0) {
+ data.code = item.split(".")[1].toLowerCase() + item.split(".")[0]
}
}
-function search(code,name){
+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 search(code, name) {
setTimeout(() => {
//window.open("https://xueqiu.com/S/"+code)
//window.open("https://www.cls.cn/stock?code="+code)
//window.open("https://quote.eastmoney.com/"+code+".html")
//window.open("https://finance.sina.com.cn/realstock/company/"+code+"/nc.shtml")
- window.open("https://www.iwencai.com/unifiedwap/result?w="+name)
+ //window.open("https://www.iwencai.com/unifiedwap/result?w=" + name)
//window.open("https://www.iwencai.com/chat/?question="+code)
+
+ openCenteredWindow("https://www.iwencai.com/unifiedwap/result?w=" + name,1000,800)
+
}, 500)
}
-function setStock(code,name){
- let res=followList.value.filter(item => item.StockCode===code)
- ////console.log("res:",res)
- formModel.value.name=name
- formModel.value.code=code
- formModel.value.volume=res[0].Volume?res[0].Volume:0
- formModel.value.costPrice=res[0].CostPrice
- formModel.value.alarm=res[0].AlarmChangePercent
- formModel.value.alarmPrice=res[0].AlarmPrice
- formModel.value.sort=res[0].Sort
- formModel.value.cron=res[0].Cron
- modalShow.value=true
+
+function setStock(code, name) {
+ let res = followList.value.filter(item => item.StockCode === code)
+ ////console.log("res:",res)
+ formModel.value.name = name
+ formModel.value.code = code
+ formModel.value.volume = res[0].Volume ? res[0].Volume : 0
+ formModel.value.costPrice = res[0].CostPrice
+ formModel.value.alarm = res[0].AlarmChangePercent
+ formModel.value.alarmPrice = res[0].AlarmPrice
+ formModel.value.sort = res[0].Sort
+ formModel.value.cron = res[0].Cron
+ modalShow.value = true
}
-function clearFeishi(){
+
+function clearFeishi() {
//console.log("clearFeishi")
clearInterval(feishiInterval.value)
}
+
function showFsChart(code, name) {
data.name = name
data.code = code
@@ -664,14 +659,14 @@ function showFsChart(code, name) {
const priceData = result.priceData
let category = []
let price = []
- let openprice=0
- let closeprice=0
+ let openprice = 0
+ let closeprice = 0
let volume = []
let volumeRate = []
let min = 0
let max = 0
- openprice=priceData[0].price
- closeprice=priceData[priceData.length-1].price
+ openprice = priceData[0].price
+ closeprice = priceData[priceData.length - 1].price
for (let i = 0; i < priceData.length; i++) {
category.push(priceData[i].time)
price.push(priceData[i].price)
@@ -682,8 +677,8 @@ function showFsChart(code, name) {
max = priceData[i].price
}
if (i > 0) {
- let b=priceData[i].volume - priceData[i - 1].volume
- volumeRate.push(((b-volume[i-1])/volume[i-1]*100).toFixed(2))
+ let b = priceData[i].volume - priceData[i - 1].volume
+ volumeRate.push(((b - volume[i - 1]) / volume[i - 1] * 100).toFixed(2))
volume.push(b)
} else {
volume.push(priceData[i].volume)
@@ -693,7 +688,7 @@ function showFsChart(code, name) {
let option = {
title: {
- subtext: "["+result.date+"] 开盘:"+openprice+" 最新:"+closeprice+" 最高:"+max+" 最低:"+min,
+ subtext: "[" + result.date + "] 开盘:" + openprice + " 最新:" + closeprice + " 最高:" + max + " 最低:" + min,
left: 'center',
top: '10',
textStyle: {
@@ -730,13 +725,13 @@ function showFsChart(code, name) {
}
},
xAxis: [
- {
- type: 'category',
- data: category,
- axisLabel: {
- show: false
- }
- },
+ {
+ type: 'category',
+ data: category,
+ axisLabel: {
+ show: false
+ }
+ },
{
gridIndex: 1,
type: 'category',
@@ -765,8 +760,8 @@ function showFsChart(code, name) {
show: false
},
name: "股价",
- min: (min - min*0.01).toFixed(2),
- max: (max + max*0.01).toFixed(2),
+ min: (min - min * 0.01).toFixed(2),
+ max: (max + max * 0.01).toFixed(2),
minInterval: 0.01,
type: 'value'
},
@@ -784,7 +779,7 @@ function showFsChart(code, name) {
],
visualMap: {
type: 'piecewise',
- seriesIndex:0,
+ seriesIndex: 0,
top: 0,
left: 10,
orient: 'horizontal',
@@ -827,13 +822,13 @@ function showFsChart(code, name) {
type: 'line',
smooth: false,
showSymbol: false,
- lineStyle: {
+ lineStyle: {
width: 3
},
markPoint: {
symbol: 'arrow',
- symbolRotate:90,
- symbolSize: [10,20],
+ symbolRotate: 90,
+ symbolSize: [10, 20],
symbolOffset: [10, 0],
itemStyle: {
color: '#FC290D'
@@ -849,24 +844,24 @@ function showFsChart(code, name) {
markLine: {
symbol: 'none',
data: [
- { type: 'average', name: 'Average' },
- {
- lineStyle:{
- color: '#FFCB00',
- width: 0.5
- },
- yAxis: openprice,
- name: '开盘价'
+ {type: 'average', name: 'Average'},
+ {
+ lineStyle: {
+ color: '#FFCB00',
+ width: 0.5
},
- {
- yAxis: closeprice ,
- symbol: 'none',
- lineStyle:{
- color: 'red',
- width: 0.5
- },
- }
- ]
+ yAxis: openprice,
+ name: '开盘价'
+ },
+ {
+ yAxis: closeprice,
+ symbol: 'none',
+ lineStyle: {
+ color: 'red',
+ width: 0.5
+ },
+ }
+ ]
},
},
{
@@ -883,30 +878,30 @@ function showFsChart(code, name) {
})
}
-function showFenshi(code,name,changePercent){
- data.code=code
- data.name=name
- data.changePercent=changePercent
- data.fenshiURL='http://image.sinajs.cn/newchart/min/n/'+data.code+'.gif'+"?t="+Date.now()
+function showFenshi(code, name, changePercent) {
+ data.code = code
+ data.name = name
+ data.changePercent = changePercent
+ data.fenshiURL = 'http://image.sinajs.cn/newchart/min/n/' + data.code + '.gif' + "?t=" + Date.now()
- if(code.startsWith('hk')){
- data.fenshiURL='http://image.sinajs.cn/newchart/hk_stock/min/'+data.code.replace("hk","")+'.gif'+"?t="+Date.now()
+ if (code.startsWith('hk')) {
+ data.fenshiURL = 'http://image.sinajs.cn/newchart/hk_stock/min/' + data.code.replace("hk", "") + '.gif' + "?t=" + Date.now()
}
- if(code.startsWith('gb_')){
- data.fenshiURL='http://image.sinajs.cn/newchart/usstock/min/'+data.code.replace("gb_","")+'.gif'+"?t="+Date.now()
+ if (code.startsWith('gb_')) {
+ data.fenshiURL = 'http://image.sinajs.cn/newchart/usstock/min/' + data.code.replace("gb_", "") + '.gif' + "?t=" + Date.now()
}
- modalShow2.value=true
+ modalShow2.value = true
}
-function handleFeishi(){
+function handleFeishi() {
showFsChart(data.code, data.name);
- feishiInterval.value=setInterval(() => {
+ feishiInterval.value = setInterval(() => {
showFsChart(data.code, data.name);
- }, 1000*10)
+ }, 1000 * 10)
}
-function calculateMA(dayCount,values) {
+function calculateMA(dayCount, values) {
var result = [];
for (var i = 0, len = values.length; i < len; i++) {
if (i < dayCount) {
@@ -921,39 +916,40 @@ function calculateMA(dayCount,values) {
}
return result;
}
-function handleKLine(){
- GetStockKLine(data.code,data.name,365).then(result => {
+
+function handleKLine() {
+ GetStockKLine(data.code, data.name, 365).then(result => {
//console.log("GetStockKLine",result)
const chart = echarts.init(kLineChartRef.value);
const categoryData = [];
const values = [];
- const volumns=[];
+ const volumns = [];
for (let i = 0; i < result.length; i++) {
- let resultElement=result[i]
+ let resultElement = result[i]
//console.log("resultElement:{}",resultElement)
categoryData.push(resultElement.day)
- let flag=resultElement.close>resultElement.open?1:-1
+ let flag = resultElement.close > resultElement.open ? 1 : -1
values.push([
resultElement.open,
resultElement.close,
resultElement.low,
resultElement.high
])
- volumns.push([i,resultElement.volume/10000,flag])
+ volumns.push([i, resultElement.volume / 10000, flag])
}
////console.log("categoryData",categoryData)
////console.log("values",values)
let option = {
darkMode: data.darkTheme,
//backgroundColor: '#1c1c1c',
- // color:['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
+ // color:['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
animation: false,
legend: {
bottom: 10,
left: 'center',
data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30'],
textStyle: {
- color: data.darkTheme?'#ccc':'#456'
+ color: data.darkTheme ? '#ccc' : '#456'
},
},
tooltip: {
@@ -967,19 +963,19 @@ function handleKLine(){
}
},
borderWidth: 2,
- borderColor: data.darkTheme?'#456':'#ccc',
- backgroundColor: data.darkTheme?'#456':'#fff',
+ borderColor: data.darkTheme ? '#456' : '#ccc',
+ backgroundColor: data.darkTheme ? '#456' : '#fff',
padding: 10,
textStyle: {
- color: data.darkTheme?'#ccc':'#456'
+ color: data.darkTheme ? '#ccc' : '#456'
},
formatter: function (params) {//修改鼠标划过显示为中文
//console.log("params",params)
- let volum=params[5].data;//ma5的值
- let ma5=params[1].data;//ma5的值
- let ma10=params[2].data;//ma10的值
- let ma20=params[3].data;//ma20的值
- let ma30=params[4].data;//ma30的值
+ let volum = params[5].data;//ma5的值
+ let ma5 = params[1].data;//ma5的值
+ let ma10 = params[2].data;//ma10的值
+ let ma20 = params[3].data;//ma20的值
+ let ma30 = params[4].data;//ma30的值
params = params[0];//开盘收盘最低最高数据汇总
let currentItemData = params.data;
@@ -1046,8 +1042,8 @@ function handleKLine(){
type: 'category',
data: categoryData,
boundaryGap: false,
- axisLine: { onZero: false },
- splitLine: { show: false },
+ axisLine: {onZero: false},
+ splitLine: {show: false},
min: 'dataMin',
max: 'dataMax',
axisPointer: {
@@ -1059,10 +1055,10 @@ function handleKLine(){
gridIndex: 1,
data: categoryData,
boundaryGap: false,
- axisLine: { onZero: false },
- axisTick: { show: false },
- splitLine: { show: false },
- axisLabel: { show: false },
+ axisLine: {onZero: false},
+ axisTick: {show: false},
+ splitLine: {show: false},
+ axisLabel: {show: false},
min: 'dataMin',
max: 'dataMax'
}
@@ -1078,10 +1074,10 @@ function handleKLine(){
scale: true,
gridIndex: 1,
splitNumber: 2,
- axisLabel: { show: false },
- axisLine: { show: false },
- axisTick: { show: false },
- splitLine: { show: false }
+ axisLabel: {show: false},
+ axisLine: {show: false},
+ axisTick: {show: false},
+ splitLine: {show: false}
}
],
dataZoom: [
@@ -1109,8 +1105,8 @@ function handleKLine(){
itemStyle: {
color: upColor,
color0: downColor,
- // borderColor: upBorderColor,
- // borderColor0: downBorderColor
+ // borderColor: upBorderColor,
+ // borderColor0: downBorderColor
},
markPoint: {
label: {
@@ -1191,7 +1187,7 @@ function handleKLine(){
{
name: 'MA5',
type: 'line',
- data: calculateMA(5,values),
+ data: calculateMA(5, values),
smooth: true,
showSymbol: false,
lineStyle: {
@@ -1201,7 +1197,7 @@ function handleKLine(){
{
name: 'MA10',
type: 'line',
- data: calculateMA(10,values),
+ data: calculateMA(10, values),
smooth: true,
showSymbol: false,
lineStyle: {
@@ -1211,7 +1207,7 @@ function handleKLine(){
{
name: 'MA20',
type: 'line',
- data: calculateMA(20,values),
+ data: calculateMA(20, values),
smooth: true,
showSymbol: false,
lineStyle: {
@@ -1221,7 +1217,7 @@ function handleKLine(){
{
name: 'MA30',
type: 'line',
- data: calculateMA(30,values),
+ data: calculateMA(30, values),
smooth: true,
showSymbol: false,
lineStyle: {
@@ -1241,58 +1237,57 @@ function handleKLine(){
]
};
chart.setOption(option);
- chart.on('click',{seriesName:'日K'}, function(params) {
+ chart.on('click', {seriesName: '日K'}, function (params) {
//console.log("click:",params);
});
})
}
-function showMoney(code,name){
- data.code=code
- data.name=name
- modalShow5.value=true
+
+function showMoney(code, name) {
+ data.code = code
+ data.name = name
+ modalShow5.value = true
}
-function showK(code,name){
- data.code=code
- data.name=name
- data.kURL='http://image.sinajs.cn/newchart/daily/n/'+data.code+'.gif'+"?t="+Date.now()
- if(code.startsWith('hk')){
- data.kURL='http://image.sinajs.cn/newchart/hk_stock/daily/'+data.code.replace("hk","")+'.gif'+"?t="+Date.now()
+function showK(code, name) {
+ data.code = code
+ data.name = name
+ data.kURL = 'http://image.sinajs.cn/newchart/daily/n/' + data.code + '.gif' + "?t=" + Date.now()
+ if (code.startsWith('hk')) {
+ data.kURL = 'http://image.sinajs.cn/newchart/hk_stock/daily/' + data.code.replace("hk", "") + '.gif' + "?t=" + Date.now()
}
- if(code.startsWith('gb_')){
- data.kURL='http://image.sinajs.cn/newchart/usstock/daily/'+data.code.replace("gb_","")+'.gif'+"?t="+Date.now()
+ if (code.startsWith('gb_')) {
+ data.kURL = 'http://image.sinajs.cn/newchart/usstock/daily/' + data.code.replace("gb_", "") + '.gif' + "?t=" + Date.now()
}
- modalShow3.value=true
+ modalShow3.value = true
//https://image.sinajs.cn/newchart/usstock/daily/dji.gif
//https://image.sinajs.cn/newchart/hk_stock/daily/06030.gif?1740729404273
}
-
-
-function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
-
- if(formModel.sort){
- SetStockSort(formModel.sort,code).then(result => {
+function updateCostPriceAndVolumeNew(code, price, volume, alarm, formModel) {
+ if (formModel.sort) {
+ SetStockSort(formModel.sort, code).then(result => {
//message.success(result)
})
}
- if(formModel.cron){
- SetStockAICron(formModel.cron,code).then(result => {
+ if (formModel.cron) {
+ SetStockAICron(formModel.cron, code).then(result => {
//message.success(result)
})
}
- if(alarm||formModel.alarmPrice){
- SetAlarmChangePercent(alarm,formModel.alarmPrice,code).then(result => {
+ if (alarm || formModel.alarmPrice) {
+ SetAlarmChangePercent(alarm, formModel.alarmPrice, code).then(result => {
//message.success(result)
})
}
- SetCostPriceAndVolume(code,price,volume).then(result => {
- modalShow.value=false
+ SetCostPriceAndVolume(code, price, volume).then(result => {
+ modalShow.value = false
message.success(result)
GetFollowList(currentGroupId.value).then(result => {
followList.value = result
+ stocks.value = []
for (const followedStock of result) {
if (!stocks.value.includes(followedStock.StockCode)) {
stocks.value.push(followedStock.StockCode)
@@ -1304,73 +1299,75 @@ function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
})
}
-function fullscreen(){
- if(data.fullscreen){
+function fullscreen() {
+ if (data.fullscreen) {
WindowUnfullscreen()
- }else{
+ } else {
WindowFullscreen()
}
- data.fullscreen=!data.fullscreen
+ data.fullscreen = !data.fullscreen
}
//type 报警类型: 1 涨跌报警;2 股价报警 3 成本价报警
-function SendMessage(result,type){
- let typeName=getTypeName(type)
- let img='http://image.sinajs.cn/newchart/min/n/'+result["股票代码"]+'.gif'+"?t="+Date.now()
- let markdown="### go-stock ["+typeName+"]\n\n"+
- "### "+result["股票名称"]+"("+result["股票代码"]+")\n" +
- "- 当前价格: "+result["当前价格"]+" "+result.changePercent+"%\n" +
- "- 最高价: "+result["今日最高价"]+" "+result.highRate+"\n" +
- "- 最低价: "+result["今日最低价"]+" "+result.lowRate+"\n" +
- "- 昨收价: "+result["昨日收盘价"]+"\n" +
- "- 今开价: "+result["今日开盘价"]+"\n" +
- "- 成本价: "+result.costPrice+" "+result.profit+"% "+result.profitAmount+" ¥\n" +
- "- 成本数量: "+result.costVolume+"股\n" +
- "- 日期: "+result["日期"]+" "+result["时间"]+"\n\n"+
- "\n"
- let title=result["股票名称"]+"("+result["股票代码"]+") "+result["当前价格"]+" "+result.changePercent
+function SendMessage(result, type) {
+ let typeName = getTypeName(type)
+ let img = 'http://image.sinajs.cn/newchart/min/n/' + result["股票代码"] + '.gif' + "?t=" + Date.now()
+ let markdown = "### go-stock [" + typeName + "]\n\n" +
+ "### " + result["股票名称"] + "(" + result["股票代码"] + ")\n" +
+ "- 当前价格: " + result["当前价格"] + " " + result.changePercent + "%\n" +
+ "- 最高价: " + result["今日最高价"] + " " + result.highRate + "\n" +
+ "- 最低价: " + result["今日最低价"] + " " + result.lowRate + "\n" +
+ "- 昨收价: " + result["昨日收盘价"] + "\n" +
+ "- 今开价: " + result["今日开盘价"] + "\n" +
+ "- 成本价: " + result.costPrice + " " + result.profit + "% " + result.profitAmount + " ¥\n" +
+ "- 成本数量: " + result.costVolume + "股\n" +
+ "- 日期: " + result["日期"] + " " + result["时间"] + "\n\n" +
+ "\n"
+ let title = result["股票名称"] + "(" + result["股票代码"] + ") " + result["当前价格"] + " " + result.changePercent
- let msg='{' +
+ let msg = '{' +
' "msgtype": "markdown",' +
' "markdown": {' +
- ' "title":"['+typeName+"]"+title+'",' +
- ' "text": "'+markdown+'"' +
+ ' "title":"[' + typeName + "]" + title + '",' +
+ ' "text": "' + markdown + '"' +
' },' +
' "at": {' +
' "isAtAll": true' +
' }' +
' }'
- // SendDingDingMessage(msg,result["股票代码"])
- SendDingDingMessageByType(msg,result["股票代码"],type)
+ // SendDingDingMessage(msg,result["股票代码"])
+ SendDingDingMessageByType(msg, result["股票代码"], type)
}
-function aiReCheckStock(stock,stockCode) {
- data.modelName=""
- data.airesult=""
- data.time=""
- data.name=stock
- data.code=stockCode
- data.loading=true
- modalShow4.value=true
- message.loading("ai检测中...",{
+
+function aiReCheckStock(stock, stockCode) {
+ data.modelName = ""
+ data.airesult = ""
+ data.time = ""
+ data.name = stock
+ data.code = stockCode
+ data.loading = true
+ modalShow4.value = true
+ message.loading("ai检测中...", {
duration: 0,
})
//
//message.info("sysPromptId:"+data.sysPromptId)
- NewChatStream(stock,stockCode,data.question,data.sysPromptId)
+ NewChatStream(stock, stockCode, data.question, data.sysPromptId)
}
-function aiCheckStock(stock,stockCode){
+
+function aiCheckStock(stock, stockCode) {
GetAIResponseResult(stockCode).then(result => {
- if(result.content){
- data.modelName=result.modelName
- data.chatId=result.chatId
- data.question=result.question
- data.name=stock
- data.code=stockCode
- data.loading=false
- modalShow4.value=true
- data.airesult=result.content
+ if (result.content) {
+ data.modelName = result.modelName
+ data.chatId = result.chatId
+ data.question = result.question
+ data.name = stock
+ data.code = stockCode
+ data.loading = false
+ modalShow4.value = true
+ data.airesult = result.content
const date = new Date(result.CreatedAt);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
@@ -1378,27 +1375,26 @@ function aiCheckStock(stock,stockCode){
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
- data.time=`${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
- }else{
- data.modelName=""
- data.question=""
- data.airesult=""
- data.time=""
- data.name=stock
- data.code=stockCode
- data.loading=true
- modalShow4.value=true
- message.loading("ai检测中...",{
+ data.time = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+ } else {
+ data.modelName = ""
+ data.question = ""
+ data.airesult = ""
+ data.time = ""
+ data.name = stock
+ data.code = stockCode
+ data.loading = true
+ modalShow4.value = true
+ message.loading("ai检测中...", {
duration: 0,
})
- NewChatStream(stock,stockCode,"",data.sysPromptId)
+ NewChatStream(stock, stockCode, "", data.sysPromptId)
}
})
}
-function getTypeName(type){
- switch (type)
- {
+function getTypeName(type) {
+ switch (type) {
case 1:
return "涨跌报警"
case 2:
@@ -1424,28 +1420,28 @@ window.onerror = function (msg, source, lineno, colno, error) {
lineno: lineno,
colno: colno,
error: error ? error.stack : null,
- data:data,
- results:results,
- followList:followList,
- stockList:stockList,
- stocks:stocks,
- formModel:formModel,
+ data: data,
+ results: results,
+ followList: followList,
+ stockList: stockList,
+ stocks: stocks,
+ formModel: formModel,
});
- message.error("发生错误:"+msg)
+ message.error("发生错误:" + msg)
return true;
};
-function saveAsImage(name,code) {
+function saveAsImage(name, code) {
const element = document.querySelector('.md-editor-preview');
if (element) {
- html2canvas(element,{
+ html2canvas(element, {
useCORS: true, // 解决跨域图片问题
scale: 2, // 提高截图质量
allowTaint: true, // 允许跨域图片
}).then(canvas => {
const link = document.createElement('a');
link.href = canvas.toDataURL('image/png');
- link.download = name+"["+code+']-ai-analysis-result.png';
+ link.download = name + "[" + code + ']-ai-analysis-result.png';
link.click();
});
} else {
@@ -1461,13 +1457,15 @@ async function copyToClipboard() {
message.error('复制失败: ' + err);
}
}
-function saveAsMarkdown(){
- SaveAsMarkdown(data.code,data.name).then(result => {
+
+function saveAsMarkdown() {
+ SaveAsMarkdown(data.code, data.name).then(result => {
message.success(result)
})
}
+
function saveAsMarkdown_old() {
- const blob = new Blob([data.airesult], { type: 'text/markdown;charset=utf-8' });
+ const blob = new Blob([data.airesult], {type: 'text/markdown;charset=utf-8'});
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `${data.name}[${data.code}]-${data.time}ai-analysis-result.md`;
@@ -1475,6 +1473,7 @@ function saveAsMarkdown_old() {
URL.revokeObjectURL(link.href);
link.remove()
}
+
function getHtml(ref) {
if (ref.value) {
// 获取 MdPreview 组件的根元素
@@ -1492,7 +1491,7 @@ async function saveAsWord() {
// 将富文本内容拼接为一个完整的html
const html = getHtml(mdPreviewRef)
const tipsHtml = getHtml(tipsRef)
- const value = `
+ const value = `
${html}
@@ -1506,7 +1505,7 @@ AI赋能股票分析:自选股行情获取,成本盈亏展示,涨跌报警
`
// landscape就是横着的,portrait是竖着的,默认是竖屏portrait。
- const blob = await asBlob(value, { orientation: 'portrait' })
+ const blob = await asBlob(value, {orientation: 'portrait'})
const a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = `${data.name}[${data.code}]-ai-analysis-result.docx`;
@@ -1516,8 +1515,8 @@ AI赋能股票分析:自选股行情获取,成本盈亏展示,涨跌报警
a.remove()
}
-function share(code,name){
- ShareAnalysis(code,name).then(msg => {
+function share(code, name) {
+ ShareAnalysis(code, name).then(msg => {
//message.info(msg)
notify.info({
avatar: () =>
@@ -1527,90 +1526,96 @@ function share(code,name){
src: icon.value
}),
title: '分享到社区',
- duration:1000*30,
+ duration: 1000 * 30,
content: () => {
return h('div', {
style: {
'text-align': 'left',
'font-size': '14px',
}
- }, { default: () => msg })
+ }, {default: () => msg})
},
})
})
}
-const addTabModel=ref({
+
+const addTabModel = ref({
name: '',
sort: 1,
})
-const addTabPane=ref(false)
-function addTab(){
- addTabPane.value=true
+const addTabPane = ref(false)
+
+function addTab() {
+ addTabPane.value = true
}
-function saveTabPane(){
+
+function saveTabPane() {
AddGroup(addTabModel.value).then(result => {
message.info(result)
- addTabPane.value=false
+ addTabPane.value = false
GetGroupList().then(result => {
- groupList.value=result
+ groupList.value = result
})
})
}
-function AddStockGroupInfo(groupId,code,name){
- if(code.startsWith("gb_")){
- code="us"+ code.replace("gb_", "").toLowerCase()
+
+function AddStockGroupInfo(groupId, code, name) {
+ if (code.startsWith("gb_")) {
+ code = "us" + code.replace("gb_", "").toLowerCase()
}
- AddStockGroup(groupId,code).then(result => {
+ AddStockGroup(groupId, code).then(result => {
message.info(result)
GetGroupList().then(result => {
- groupList.value=result
+ groupList.value = result
})
})
}
-function updateTab(name){
- currentGroupId.value=Number(name)
+
+function updateTab(name) {
+ currentGroupId.value = Number(name)
GetFollowList(currentGroupId.value).then(result => {
- stocks.value=[]
- //console.log("GetFollowList",result)
+ stocks.value = []
followList.value = result
for (const followedStock of result) {
- if(followedStock.StockCode.startsWith("us")){
- followedStock.StockCode="gb_"+ followedStock.StockCode.replace("us", "").toLowerCase()
+ if (followedStock.StockCode.startsWith("us")) {
+ followedStock.StockCode = "gb_" + followedStock.StockCode.replace("us", "").toLowerCase()
}
- ////console.log("followList",followedStock.StockCode)
- stocks.value.push(followedStock.StockCode)
+ ////console.log("followList",followedStock.StockCode)
+ stocks.value.push(followedStock.StockCode)
}
monitor()
message.destroyAll()
})
}
-function delTab(name){
- let infos=groupList.value=groupList.value.filter(item => item.ID === Number(name))
+
+function delTab(name) {
+ let infos = groupList.value = groupList.value.filter(item => item.ID === Number(name))
dialog.create({
title: '删除分组',
type: 'warning',
- content: '确定要删除['+infos[0].name+']分组吗?分组数据将不能恢复哟!',
+ content: '确定要删除[' + infos[0].name + ']分组吗?分组数据将不能恢复哟!',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
RemoveGroup(name).then(result => {
message.info(result)
GetGroupList().then(result => {
- groupList.value=result
+ groupList.value = result
})
})
}
})
}
-function delStockGroup(code,name,groupId){
- RemoveStockGroup(code,name,groupId).then(result => {
+
+function delStockGroup(code, name, groupId) {
+ RemoveStockGroup(code, name, groupId).then(result => {
updateTab(groupId)
message.info(result)
})
}
-function searchNotice(stockCode){
+function searchNotice(stockCode) {
router.push({
name: 'market',
query: {
@@ -1619,7 +1624,8 @@ function searchNotice(stockCode){
},
})
}
-function searchStockReport(stockCode){
+
+function searchStockReport(stockCode) {
router.push({
name: 'market',
query: {
@@ -1631,384 +1637,447 @@ function searchStockReport(stockCode){
-
-
-
- {{ danmu }}
-
-
-
- {delTab(key)}">
-
-
-
-
-
-
-
-
- ({{result['盘前盘后']}} {{result['盘前盘后涨跌幅']}}%)
-
-
- %
-
-
-
-
-
-
-
-
- {{"最高 "+result["今日最高价"]+" "+result.highRate }}%
-
-
- {{"最低 "+result["今日最低价"]+" "+result.lowRate }}%
-
-
- {{"昨收 "+result["昨日收盘价"]}}
-
-
- {{"今开 "+result["今日开盘价"]}}
-
-
-
-
-
-
- {{"买一 "+result["买一报价"]+'('+result["买一申报"]+")"}}
- {{"卖一 "+result["卖一报价"]+'('+result["卖一申报"]+")"}}
-
-
-
-
- {{"买一 "+result["买一报价"]+'('+result["买一申报"]+")"}}
-
-
- {{"卖一 "+result["卖一报价"]+'('+result["卖一申报"]+")"}}
-
-
-
- {{"买二 "+result["买二报价"]+'('+result["买二申报"]+")"}}
-
-
- {{"卖二 "+result["卖二报价"]+'('+result["卖二申报"]+")"}}
-
-
-
- {{"买三 "+result["买三报价"]+'('+result["买三申报"]+")"}}
-
-
- {{"买三 "+result["卖三报价"]+'('+result["卖三申报"]+")"}}
-
-
-
- {{"买四 "+result["买四报价"]+'('+result["买四申报"]+")"}}
-
-
- {{"卖四 "+result["卖四报价"]+'('+result["卖四申报"]+")"}}
-
-
-
- {{"买五 "+result["买五报价"]+'('+result["买五申报"]+")"}}
-
-
- {{"卖五 "+result["卖五报价"]+'('+result["卖五申报"]+")"}}
-
-
-
-
-
-
- {{result['股票代码']}}
-
- 取消关注
-
-
- AI分析
-
-
-
-
-
- {{result["日期"]+" "+result["时间"]}}
- {{result.volume+"股"}}
- {{"成本:"+result.costPrice+"*"+result.costVolume+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}
-
-
-
-
- 成本
- 分时
- 日K
- 资金
- 详情
- 公告
- 研报
-
- AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
- 设置分组
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {{ danmu }}
+
+
+
+ {delTab(key)}">
+
+
+
+
-
-
- ({{result['盘前盘后']}} {{result['盘前盘后涨跌幅']}}%)
+
+
+
+ ({{ result['盘前盘后'] }} {{ result['盘前盘后涨跌幅'] }}%)
+
- %
+
+ %
-
+
-
+
- {{"最高 "+result["今日最高价"]+" "+result.highRate }}%
+ {{ "最高 " + result["今日最高价"] + " " + result.highRate }}%
- {{"最低 "+result["今日最低价"]+" "+result.lowRate }}%
+ {{ "最低 " + result["今日最低价"] + " " + result.lowRate }}%
- {{"昨收 "+result["昨日收盘价"]}}
+ {{ "昨收 " + result["昨日收盘价"] }}
- {{"今开 "+result["今日开盘价"]}}
+ {{ "今开 " + result["今日开盘价"] }}
- {{"买一 "+result["买一报价"]+'('+result["买一申报"]+")"}}
- {{"卖一 "+result["卖一报价"]+'('+result["卖一申报"]+")"}}
+ {{ "买一 " + result["买一报价"] + '(' + result["买一申报"] + ")" }}
+ {{ "卖一 " + result["卖一报价"] + '(' + result["卖一申报"] + ")" }}
-
+
- {{"买一 "+result["买一报价"]+'('+result["买一申报"]+")"}}
+ {{ "买一 " + result["买一报价"] + '(' + result["买一申报"] + ")" }}
- {{"卖一 "+result["卖一报价"]+'('+result["卖一申报"]+")"}}
+ {{ "卖一 " + result["卖一报价"] + '(' + result["卖一申报"] + ")" }}
- {{"买二 "+result["买二报价"]+'('+result["买二申报"]+")"}}
+ {{ "买二 " + result["买二报价"] + '(' + result["买二申报"] + ")" }}
- {{"卖二 "+result["卖二报价"]+'('+result["卖二申报"]+")"}}
+ {{ "卖二 " + result["卖二报价"] + '(' + result["卖二申报"] + ")" }}
- {{"买三 "+result["买三报价"]+'('+result["买三申报"]+")"}}
+ {{ "买三 " + result["买三报价"] + '(' + result["买三申报"] + ")" }}
- {{"买三 "+result["卖三报价"]+'('+result["卖三申报"]+")"}}
+ {{ "买三 " + result["卖三报价"] + '(' + result["卖三申报"] + ")" }}
- {{"买四 "+result["买四报价"]+'('+result["买四申报"]+")"}}
+ {{ "买四 " + result["买四报价"] + '(' + result["买四申报"] + ")" }}
- {{"卖四 "+result["卖四报价"]+'('+result["卖四申报"]+")"}}
+ {{ "卖四 " + result["卖四报价"] + '(' + result["卖四申报"] + ")" }}
- {{"买五 "+result["买五报价"]+'('+result["买五申报"]+")"}}
+ {{ "买五 " + result["买五报价"] + '(' + result["买五申报"] + ")" }}
- {{"卖五 "+result["卖五报价"]+'('+result["卖五申报"]+")"}}
+ {{ "卖五 " + result["卖五报价"] + '(' + result["卖五申报"] + ")" }}
- {{result['股票代码']}}
-
+ {{ result['股票代码'] }}
+
取消关注
-
+
AI分析
-
- 移出分组
+
+
- {{result["日期"]+" "+result["时间"]}}
- {{result.volume+"股"}}
- {{"成本:"+result.costPrice+"*"+result.costVolume+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}
+ {{ result["日期"] + " " + result["时间"] }}
+ {{ result.volume + "股" }}
+
+ {{ "成本:" + result.costPrice + "*" + result.costVolume + " " + result.profit + "%" + " ( " + result.profitAmount + " ¥ )" }}
+
- 成本
- 分时
- 日K
- 资金
- 详情
- 公告
- 研报
+ 成本
+
+ 分时
+
+ 日K
+ 资金
+
+ 详情
+
+ 公告
+
+ 研报
+
- AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
- 设置分组
+ AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
+ 设置分组
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ({{ result['盘前盘后'] }} {{ result['盘前盘后涨跌幅'] }}%)
+
+
+
+
+ %
+
+
+
+
+
+
+
+
+ {{ "最高 " + result["今日最高价"] + " " + result.highRate }}%
+
+
+ {{ "最低 " + result["今日最低价"] + " " + result.lowRate }}%
+
+
+ {{ "昨收 " + result["昨日收盘价"] }}
+
+
+ {{ "今开 " + result["今日开盘价"] }}
+
+
+
+
+
+
+ {{ "买一 " + result["买一报价"] + '(' + result["买一申报"] + ")" }}
+ {{ "卖一 " + result["卖一报价"] + '(' + result["卖一申报"] + ")" }}
+
+
+
+
+ {{ "买一 " + result["买一报价"] + '(' + result["买一申报"] + ")" }}
+
+
+ {{ "卖一 " + result["卖一报价"] + '(' + result["卖一申报"] + ")" }}
+
+
+
+ {{ "买二 " + result["买二报价"] + '(' + result["买二申报"] + ")" }}
+
+
+ {{ "卖二 " + result["卖二报价"] + '(' + result["卖二申报"] + ")" }}
+
+
+
+ {{ "买三 " + result["买三报价"] + '(' + result["买三申报"] + ")" }}
+
+
+ {{ "买三 " + result["卖三报价"] + '(' + result["卖三申报"] + ")" }}
+
+
+
+ {{ "买四 " + result["买四报价"] + '(' + result["买四申报"] + ")" }}
+
+
+ {{ "卖四 " + result["卖四报价"] + '(' + result["卖四申报"] + ")" }}
+
+
+
+ {{ "买五 " + result["买五报价"] + '(' + result["买五申报"] + ")" }}
+
+
+ {{ "卖五 " + result["卖五报价"] + '(' + result["卖五申报"] + ")" }}
+
+
+
+
+
+
+ {{ result['股票代码'] }}
+
+ 取消关注
+
+
+ AI分析
+
+ 移出分组
+
+
+
+
+ {{ result["日期"] + " " + result["时间"] }}
+ {{ result.volume + "股" }}
+
+ {{ "成本:" + result.costPrice + "*" + result.costVolume + " " + result.profit + "%" + " ( " + result.profitAmount + " ¥ )" }}
+
+
+
+
+
+ 成本
+
+ 分时
+
+ 日K
+ 资金
+
+ 详情
+
+ 公告
+
+ 研报
+
+
+ AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
+ 设置分组
+
+
+
+
+
-
-
-
+
+
+
-
+ :options="options"
+ placeholder="股票指数名称/代码/弹幕"
+ clearable @update-value="getStockList" :on-select="onSelect"/>
-
-
-
- 关注
-
-
- 输入股票名称/代码关键词开始吧~~~
-
+
+
+
+ 关注
+
+
+ 输入股票名称/代码关键词开始吧~~~
+
-
- 发送弹幕
-
-
-
+
+ 发送弹幕
+
+
+
-
-
+
-
-
-
- {{formModel.code.indexOf("hk")>=0?"HK$":"¥"}}
-
-
-
-
-
-
- 股
-
-
-
-
-
-
- %
-
-
-
-
-
-
- {{formModel.code.indexOf("hk")>=0?"HK$":"¥"}}
-
-
-
-
-
-
-
-
-
-
-
-
- 保存
-
-
+
+
+
+ {{ formModel.code.indexOf("hk") >= 0 ? "HK$" : "¥" }}
+
+
+
+
+
+
+ 股
+
+
+
+
+
+
+ %
+
+
+
+
+
+
+ {{ formModel.code.indexOf("hk") >= 0 ? "HK$" : "¥" }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+
+ >
+
-
+
-
+
-
+
-
+
保存
-
+
取消
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
-
+
+
-
- {{data.modelName}}
- {{data.time}}
+
+
+ {{ data.modelName }}
+
+ {{ data.time }}
- *AI分析结果仅供参考,请以实际行情为准。投资需谨慎,风险自担。
+ *AI分析结果仅供参考,请以实际行情为准。投资需谨慎,风险自担。
-
-
+
+
-
-
- 再次分析
+
+ 再次分析
保存为图片
复制到剪切板
保存为Markdown文件
@@ -2028,33 +2097,35 @@ function searchStockReport(stockCode){
-
+
diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts
index 4e2757e..a807d0e 100644
--- a/frontend/wailsjs/go/main/App.d.ts
+++ b/frontend/wailsjs/go/main/App.d.ts
@@ -15,6 +15,8 @@ export function AnalyzeSentiment(arg1:string):Promise
;
export function CheckUpdate():Promise;
+export function ClsCalendar():Promise>;
+
export function DelPrompt(arg1:number):Promise;
export function EMDictCode(arg1:string):Promise>;
@@ -65,8 +67,16 @@ export function GlobalStockIndexes():Promise>;
export function Greet(arg1:string):Promise;
+export function HotEvent(arg1:number):Promise;
+
+export function HotStock(arg1:string):Promise;
+
+export function HotTopic(arg1:number):Promise>;
+
export function IndustryResearchReport(arg1:string):Promise>;
+export function InvestCalendarTimeLine(arg1:string):Promise>;
+
export function LongTigerRank(arg1:string):Promise;
export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise;
@@ -83,6 +93,8 @@ export function SaveAIResponseResult(arg1:string,arg2:string,arg3:string,arg4:st
export function SaveAsMarkdown(arg1:string,arg2:string):Promise;
+export function SearchStock(arg1:string):Promise>;
+
export function SendDingDingMessage(arg1:string,arg2:string):Promise;
export function SendDingDingMessageByType(arg1:string,arg2:string,arg3:number):Promise;
diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js
index 27d7441..da3813b 100644
--- a/frontend/wailsjs/go/main/App.js
+++ b/frontend/wailsjs/go/main/App.js
@@ -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);
}