From 0d3fd4755234d5e4de3d81addd9835e7a2b013d5 Mon Sep 17 00:00:00 2001 From: ArvinLovegood Date: Wed, 18 Jun 2025 18:33:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(market):=E6=B7=BB=E5=8A=A0=E8=A1=8C?= =?UTF-8?q?=E4=B8=9A=E7=A0=94=E7=A9=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 App.vue 中添加行业研究选项 - 在 market.vue 中实现行业研究页面布局 - 新增 IndustryResearchReportList 组件用于显示行业研究列表 - 在 app_common.go 中添加相关 API 接口 - 在 market_news_api.go 中实现行业研究数据获取逻辑 - 更新 README.md,添加行业研究功能说明 --- README.md | 2 +- app_common.go | 7 ++ backend/data/market_news_api.go | 92 ++++++++++++-- backend/data/market_news_api_test.go | 18 +++ backend/data/openai_api_test.go | 2 +- backend/data/stock_data_api_test.go | 8 +- frontend/src/App.vue | 21 ++++ .../components/IndustryResearchReportList.vue | 115 ++++++++++++++++++ frontend/src/components/market.vue | 5 + frontend/wailsjs/go/main/App.d.ts | 4 + frontend/wailsjs/go/main/App.js | 8 ++ 11 files changed, 266 insertions(+), 16 deletions(-) create mode 100644 frontend/src/components/IndustryResearchReportList.vue diff --git a/README.md b/README.md index 6895a4a..e8511ef 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ ## 👀 更新日志 -### 2025.06.18 更新内置股票基础数据,软件内实时市场资讯信息提醒 +### 2025.06.18 更新内置股票基础数据,软件内实时市场资讯信息提醒,添加行业研究功能 ### 2025.06.15 添加公司公告信息搜索/查看功能 ### 2025.06.15 添加个股研报到弹出菜单 ### 2025.06.13 添加个股研报功能 diff --git a/app_common.go b/app_common.go index d3a652a..d6d7e58 100644 --- a/app_common.go +++ b/app_common.go @@ -20,3 +20,10 @@ func (a *App) StockResearchReport(stockCode string) []any { func (a *App) StockNotice(stockCode string) []any { return data.NewMarketNewsApi().StockNotice(stockCode) } + +func (a *App) IndustryResearchReport(industryCode string) []any { + return data.NewMarketNewsApi().IndustryResearchReport(industryCode, 7) +} +func (a App) EMDictCode(code string) []any { + return data.NewMarketNewsApi().EMDictCode(code, a.cache) +} diff --git a/backend/data/market_news_api.go b/backend/data/market_news_api.go index f6d3c49..b8f144a 100644 --- a/backend/data/market_news_api.go +++ b/backend/data/market_news_api.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "github.com/PuerkitoBio/goquery" + "github.com/coocood/freecache" "github.com/duke-git/lancet/v2/convertor" "github.com/duke-git/lancet/v2/strutil" "github.com/go-resty/resty/v2" @@ -141,11 +142,10 @@ func (m MarketNewsApi) GetSinaNews(crawlTimeOut uint) *[]models.Telegraph { SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.60"). Get("https://zhibo.sina.com.cn/api/zhibo/feed?callback=callback&page=1&page_size=20&zhibo_id=152&tag_id=0&dire=f&dpc=1&pagesize=20&id=4161089&type=0&_=" + strconv.FormatInt(time.Now().Unix(), 10)) js := string(response.Body()) - js = strutil.ReplaceWithMap(js, - map[string]string{ - "try{callback(": "var data=", - ");}catch(e){};": ";", - }) + js = strutil.ReplaceWithMap(js, map[string]string{ + "try{callback(": "var data=", + ");}catch(e){};": ";", + }) //logger.SugaredLogger.Info(js) vm := otto.New() _, err := vm.Run(js) @@ -304,7 +304,7 @@ func (m MarketNewsApi) TopStocksRankingList(date string) { SetHeader("Referer", "https://finance.sina.com.cn"). SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.60").Get(url) - html, _ := (convertor.GbkToUtf8(response.Body())) + html, _ := convertor.GbkToUtf8(response.Body()) //logger.SugaredLogger.Infof("html:%s", html) document, err := goquery.NewDocumentFromReader(bytes.NewReader(html)) if err != nil { @@ -347,11 +347,10 @@ func (m MarketNewsApi) LongTiger(date string) *[]models.LongTigerRankData { js := string(resp.Body()) logger.SugaredLogger.Infof("resp:%s", js) - js = strutil.ReplaceWithMap(js, - map[string]string{ - "callback(": "var data=", - ");": ";", - }) + js = strutil.ReplaceWithMap(js, map[string]string{ + "callback(": "var data=", + ");": ";", + }) //logger.SugaredLogger.Info(js) vm := otto.New() _, err = vm.Run(js) @@ -378,6 +377,46 @@ func (m MarketNewsApi) LongTiger(date string) *[]models.LongTigerRankData { return ranks } +func (m MarketNewsApi) IndustryResearchReport(industryCode string, days int) []any { + beginDate := time.Now().Add(-time.Duration(days) * 24 * time.Hour).Format("2006-01-02") + endDate := time.Now().Format("2006-01-02") + if strutil.Trim(industryCode) != "" { + beginDate = time.Now().Add(-time.Duration(days) * 365 * time.Hour).Format("2006-01-02") + } + + logger.SugaredLogger.Infof("IndustryResearchReport-name:%s", industryCode) + params := map[string]string{ + "industry": "*", + "industryCode": industryCode, + "beginTime": beginDate, + "endTime": endDate, + "pageNo": "1", + "pageSize": "50", + "p": "1", + "pageNum": "1", + "pageNumber": "1", + "qType": "1", + } + + url := "https://reportapi.eastmoney.com/report/list" + + logger.SugaredLogger.Infof("beginDate:%s endDate:%s", beginDate, endDate) + resp, err := resty.New().SetTimeout(time.Duration(15)*time.Second).R(). + SetHeader("Host", "reportapi.eastmoney.com"). + SetHeader("Origin", "https://data.eastmoney.com"). + SetHeader("Referer", "https://data.eastmoney.com/report/stock.jshtml"). + 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"). + SetQueryParams(params).Get(url) + respMap := map[string]any{} + + if err != nil { + return []any{} + } + json.Unmarshal(resp.Body(), &respMap) + //logger.SugaredLogger.Infof("resp:%+v", respMap["data"]) + return respMap["data"].([]any) +} func (m MarketNewsApi) StockResearchReport(stockCode string, days int) []any { beginDate := time.Now().Add(-time.Duration(days) * 24 * time.Hour).Format("2006-01-02") endDate := time.Now().Format("2006-01-02") @@ -458,3 +497,34 @@ func (m MarketNewsApi) StockNotice(stock_list string) []any { //logger.SugaredLogger.Infof("resp:%+v", respMap["data"]) return (respMap["data"].(map[string]any))["list"].([]any) } + +func (m MarketNewsApi) EMDictCode(code string, cache *freecache.Cache) []any { + respMap := map[string]any{} + + d, _ := cache.Get([]byte(code)) + if d != nil { + json.Unmarshal(d, &respMap) + return respMap["data"].([]any) + } + + url := "https://reportapi.eastmoney.com/report/bk" + + params := map[string]string{ + "bkCode": code, + } + resp, err := resty.New().SetTimeout(time.Duration(15)*time.Second).R(). + SetHeader("Host", "reportapi.eastmoney.com"). + SetHeader("Origin", "https://data.eastmoney.com"). + SetHeader("Referer", "https://data.eastmoney.com/report/industry.jshtml"). + 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"). + SetQueryParams(params).Get(url) + + if err != nil { + return []any{} + } + json.Unmarshal(resp.Body(), &respMap) + //logger.SugaredLogger.Infof("resp:%+v", respMap["data"]) + cache.Set([]byte(code), resp.Body(), 60*60*24) + return respMap["data"].([]any) +} diff --git a/backend/data/market_news_api_test.go b/backend/data/market_news_api_test.go index 5513961..06ea3a5 100644 --- a/backend/data/market_news_api_test.go +++ b/backend/data/market_news_api_test.go @@ -73,6 +73,15 @@ func TestStockResearchReport(t *testing.T) { } } +func TestIndustryResearchReport(t *testing.T) { + db.Init("../../data/stock.db") + resp := NewMarketNewsApi().IndustryResearchReport("", 7) + for _, a := range resp { + logger.SugaredLogger.Debugf("value: %+v", a) + } + +} + func TestStockNotice(t *testing.T) { db.Init("../../data/stock.db") resp := NewMarketNewsApi().StockNotice("600584,600900") @@ -81,3 +90,12 @@ func TestStockNotice(t *testing.T) { } } + +func TestEMDictCode(t *testing.T) { + db.Init("../../data/stock.db") + resp := NewMarketNewsApi().EMDictCode("016") + for _, a := range resp { + logger.SugaredLogger.Debugf("value: %+v", a) + } + +} diff --git a/backend/data/openai_api_test.go b/backend/data/openai_api_test.go index 046ca8e..46880ed 100644 --- a/backend/data/openai_api_test.go +++ b/backend/data/openai_api_test.go @@ -24,7 +24,7 @@ func TestGetTopNewsList(t *testing.T) { } func TestSearchGuShiTongStockInfo(t *testing.T) { - //db.Init("../../data/stock.db") + db.Init("../../data/stock.db") SearchGuShiTongStockInfo("hk01810", 60) SearchGuShiTongStockInfo("sh600745", 60) SearchGuShiTongStockInfo("gb_goog", 60) diff --git a/backend/data/stock_data_api_test.go b/backend/data/stock_data_api_test.go index 483b395..817c525 100644 --- a/backend/data/stock_data_api_test.go +++ b/backend/data/stock_data_api_test.go @@ -47,6 +47,7 @@ func TestGetFinancialReports(t *testing.T) { } func TestGetTelegraphSearch(t *testing.T) { + db.Init("../../data/stock.db") //url := "https://www.cls.cn/searchPage?keyword=%E9%97%BB%E6%B3%B0%E7%A7%91%E6%8A%80&type=telegram" messages := SearchStockInfo("谷歌", "telegram", 30) for _, message := range *messages { @@ -56,16 +57,17 @@ func TestGetTelegraphSearch(t *testing.T) { //https://www.cls.cn/stock?code=sh600745 } func TestSearchStockInfoByCode(t *testing.T) { + db.Init("../../data/stock.db") SearchStockInfoByCode("sh600745") } func TestSearchStockPriceInfo(t *testing.T) { db.Init("../../data/stock.db") //SearchStockPriceInfo("中信证券", "hk06030", 30) - //SearchStockPriceInfo("上海贝岭", "sh600171", 30) - SearchStockPriceInfo("苹果公司", "gb_aapl", 30) + SearchStockPriceInfo("上海贝岭", "sh600171", 30) + //SearchStockPriceInfo("苹果公司", "gb_aapl", 30) //SearchStockPriceInfo("微创光电", "bj430198", 30) - getZSInfo("创业板指数", "sz399006", 30) + //getZSInfo("创业板指数", "sz399006", 30) //getZSInfo("上证综合指数", "sh000001", 30) //getZSInfo("沪深300指数", "sh000300", 30) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index aed2fd3..56ba11e 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -285,6 +285,27 @@ const menuOptions = ref([ key: 'market8', icon: renderIcon(NewspaperSharp), }, + { + label: () => + h( + RouterLink, + { + href: '#', + to: { + name: 'market', + query: { + name: "行业研究", + } + }, + onClick: () => { + EventsEmit("changeMarketTab", {ID: 0, name: '行业研究'}) + }, + }, + {default: () => '行业研究',} + ), + key: 'market9', + icon: renderIcon(NewspaperSharp), + }, ] }, { diff --git a/frontend/src/components/IndustryResearchReportList.vue b/frontend/src/components/IndustryResearchReportList.vue new file mode 100644 index 0000000..6103291 --- /dev/null +++ b/frontend/src/components/IndustryResearchReportList.vue @@ -0,0 +1,115 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/components/market.vue b/frontend/src/components/market.vue index d74170c..2be0268 100644 --- a/frontend/src/components/market.vue +++ b/frontend/src/components/market.vue @@ -25,6 +25,7 @@ import IndustryMoneyRank from "./industryMoneyRank.vue"; import StockResearchReportList from "./StockResearchReportList.vue"; import StockNoticeList from "./StockNoticeList.vue"; import LongTigerRankList from "./LongTigerRankList.vue"; +import IndustryResearchReportList from "./IndustryResearchReportList.vue"; const route = useRoute() const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png'); @@ -551,6 +552,10 @@ function ReFlesh(source) { + + + + diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index 2debde3..b2c0c97 100644 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -15,6 +15,8 @@ export function CheckUpdate():Promise; export function DelPrompt(arg1:number):Promise; +export function EMDictCode(arg1:string):Promise>; + export function ExportConfig():Promise; export function Follow(arg1:string):Promise; @@ -61,6 +63,8 @@ export function GlobalStockIndexes():Promise>; export function Greet(arg1:string):Promise; +export function IndustryResearchReport(arg1:string):Promise>; + export function LongTigerRank(arg1:string):Promise; export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index 2a37d4f..cb19f3f 100644 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -26,6 +26,10 @@ export function DelPrompt(arg1) { return window['go']['main']['App']['DelPrompt'](arg1); } +export function EMDictCode(arg1) { + return window['go']['main']['App']['EMDictCode'](arg1); +} + export function ExportConfig() { return window['go']['main']['App']['ExportConfig'](); } @@ -118,6 +122,10 @@ export function Greet(arg1) { return window['go']['main']['App']['Greet'](arg1); } +export function IndustryResearchReport(arg1) { + return window['go']['main']['App']['IndustryResearchReport'](arg1); +} + export function LongTigerRank(arg1) { return window['go']['main']['App']['LongTigerRank'](arg1); }