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 @@
+
+
+
+
+
+
+
+
+
+
+
+ 行业
+ 标题
+ 东财评级
+ 评级变动
+ 机构评级
+ 分析师
+ 机构
+ 日期
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.industryName}}
+
+ {{item.title}}
+
+
+ {{item.emRatingName}}
+
+ {{ratingChangeName(item.ratingChange)}}
+ {{item.sRatingName }}
+ {{item.researcher}}
+ {{item.orgSName}}
+ {{item.publishDate.substring(0,10)}}
+
+
+
+
+
+
\ 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);
}