mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
Compare commits
No commits in common. "master" and "v2025.4.25.3-alpha" have entirely different histories.
master
...
v2025.4.25
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -4,7 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
# Match any new tag
|
# Match any new tag
|
||||||
- '*-release'
|
- '*'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Necessary for most environments as build failure can occur due to OOM issues
|
# Necessary for most environments as build failure can occur due to OOM issues
|
||||||
@ -47,4 +47,4 @@ jobs:
|
|||||||
go-version: '1.24'
|
go-version: '1.24'
|
||||||
build-tags: ${{ github.ref_name }}
|
build-tags: ${{ github.ref_name }}
|
||||||
build-commit-message: ${{ steps.get_commit_message.outputs.commit_message }}
|
build-commit-message: ${{ steps.get_commit_message.outputs.commit_message }}
|
||||||
node-version: '20.x'
|
node-version: '18.x'
|
||||||
|
38
README.md
38
README.md
@ -1,17 +1,16 @@
|
|||||||
# go-stock : 基于大语言模型的AI赋能股票分析工具
|
# go-stock : 基于Wails和NaiveUI构建的AI赋能股票分析工具
|
||||||
## 
|
## 
|
||||||

|

|
||||||
[](https://github.com/ArvinLovegood/go-stock)
|
[](https://github.com/ArvinLovegood/go-stock)
|
||||||
[](https://gitee.com/arvinlovegood_admin/go-stock)
|
[](https://gitee.com/arvinlovegood_admin/go-stock)
|
||||||
|
[](https://gitcode.com/ArvinLovegood/go-stock)
|
||||||
[//]: # ([](https://gitcode.com/ArvinLovegood/go-stock))
|
|
||||||
|
|
||||||
### 🌟公众号
|
### 🌟公众号
|
||||||

|

|
||||||
|
|
||||||
### 📈 交流群
|
### 📈 交流群
|
||||||
- QQ交流群2:[点击链接加入群聊【go-stock交流群2】:892666282](https://qm.qq.com/q/5mYiy6Yxh0)
|
QQ交流群:[点击链接加入群聊【go-stock交流群】:491605333](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0YQ8qD3exahsD4YLNhzQTWe5ssstWC89&authKey=usOMMRFtIQDC%2FYcatHYapcxQbJ7PwXPHK9OypTXWzNjAq%2FRVvQu9bj2lRgb%2BSZ3p&noverify=0&group_code=491605333)
|
||||||
- QQ交流群:[点击链接加入群聊【go-stock交流群】:491605333(已满会定期清理,随缘入群)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0YQ8qD3exahsD4YLNhzQTWe5ssstWC89&authKey=usOMMRFtIQDC%2FYcatHYapcxQbJ7PwXPHK9OypTXWzNjAq%2FRVvQu9bj2lRgb%2BSZ3p&noverify=0&group_code=491605333)
|
|
||||||
|
|
||||||
### ✨ 简介
|
### ✨ 简介
|
||||||
- 本项目基于Wails和NaiveUI开发,结合AI大模型构建的股票分析工具。
|
- 本项目基于Wails和NaiveUI开发,结合AI大模型构建的股票分析工具。
|
||||||
@ -27,16 +26,15 @@
|
|||||||
|
|
||||||
### 💬 支持大模型/平台
|
### 💬 支持大模型/平台
|
||||||
| 模型 | 状态 | 备注 |
|
| 模型 | 状态 | 备注 |
|
||||||
| --- | --- |---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
| --- | --- |-----------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| [OpenAI](https://platform.openai.com/) | ✅ | 可接入任何 OpenAI 接口格式模型 |
|
| [OpenAI](https://platform.openai.com/) | ✅ | 可接入任何 OpenAI 接口格式模型 |
|
||||||
| [Ollama](https://ollama.com/) | ✅ | 本地大模型运行平台 |
|
| [Ollama](https://ollama.com/) | ✅ | 本地大模型运行平台 |
|
||||||
| [LMStudio](https://lmstudio.ai/) | ✅ | 本地大模型运行平台 |
|
| [LMStudio](https://lmstudio.ai/) | ✅ | 本地大模型运行平台 |
|
||||||
| [AnythingLLM](https://anythingllm.com/) | ✅ | 本地知识库 |
|
| [AnythingLLM](https://anythingllm.com/) | ✅ | 本地知识库 |
|
||||||
| [DeepSeek](https://www.deepseek.com/) | ✅ | deepseek-reasoner,deepseek-chat |
|
| [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) |
|
| [大模型聚合平台](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) |
|
||||||
|
|
||||||
### <span style="color: #568DF4;">各位亲爱的朋友们,如果您对这个项目感兴趣,请先给我一个<i style="color: #EA2626;">star</i>吧,谢谢!</span>💕
|
### <span style="color: #568DF4;">各位亲爱的朋友们,如果您对这个项目感兴趣,请先给我一个<i style="color: #EA2626;">star</i>吧,谢谢!</span>💕
|
||||||
- 优云智算(by UCloud):万卡规模4090免费用10小时,新人注册另增50万tokens,海量热门源项目镜像一键部署,[注册链接](https://www.compshare.cn/image-community?ytag=GPU_YY-gh_gostock)
|
|
||||||
- 经测试目前硅基流动(siliconflow)提供的deepSeek api 服务比较稳定,注册即送2000万Tokens,[注册链接](https://cloud.siliconflow.cn/i/foufCerk)
|
- 经测试目前硅基流动(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)
|
- 火山方舟:每个模型注册即送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)
|
- Tushare大数据开放社区,免费提供各类金融数据,助力行业和量化研究(注意:Tushare只需要120积分即可,注册完成个人资料补充即可得120积分!!!),[注册链接](https://tushare.pro/register?reg=701944)
|
||||||
@ -47,34 +45,14 @@
|
|||||||
## 🧩 重大功能开发计划
|
## 🧩 重大功能开发计划
|
||||||
| 功能说明 | 状态 | 备注 |
|
| 功能说明 | 状态 | 备注 |
|
||||||
|-----------------|----|----------------------------------------------------------------------------------------------------------|
|
|-----------------|----|----------------------------------------------------------------------------------------------------------|
|
||||||
| 股票分析知识库 | 🚧 | 未来计划 |
|
|
||||||
| Ai智能选股 | 🚧 | Ai智能选股功能开发中(下半年重点开发计划) |
|
|
||||||
| ETF支持 | 🚧 | ETF数据支持 (目前可以查看净值和估值) |
|
| ETF支持 | 🚧 | ETF数据支持 (目前可以查看净值和估值) |
|
||||||
| 美股支持 | ✅ | 美股数据支持 |
|
| 美股支持 | ✅ | 美股数据支持 |
|
||||||
| 港股支持 | ✅ | 港股数据支持 |
|
| 港股支持 | ✅ | 港股数据支持 (目前有延迟) |
|
||||||
| 多轮对话 | ✅ | AI分析后可继续对话提问 |
|
| 多轮对话 | ✅ | AI分析后可继续对话提问 |
|
||||||
| 自定义AI分析提问模板 | ✅ | 可配置的提问模板 [v2025.2.12.7-alpha](https://github.com/ArvinLovegood/go-stock/releases/tag/v2025.2.12.7-alpha) |
|
| 自定义AI分析提问模板 | ✅ | 可配置的提问模板 [v2025.2.12.7-alpha](https://github.com/ArvinLovegood/go-stock/releases/tag/v2025.2.12.7-alpha) |
|
||||||
| 不再强制依赖Chrome浏览器 | ✅ | 默认使用edge浏览器抓取新闻资讯 |
|
| 不再强制依赖Chrome浏览器 | ✅ | 默认使用edge浏览器抓取新闻资讯 |
|
||||||
|
|
||||||
## 👀 更新日志
|
## 👀 更新日志
|
||||||
### 2025.06.30 添加指标选股功能
|
|
||||||
### 2025.06.27 添加财经日历和重大事件时间轴功能
|
|
||||||
### 2025.06.25 添加热门股票、事件和话题功能
|
|
||||||
### 2025.06.18 更新内置股票基础数据,软件内实时市场资讯信息提醒,添加行业研究功能
|
|
||||||
### 2025.06.15 添加公司公告信息搜索/查看功能
|
|
||||||
### 2025.06.15 添加个股研报到弹出菜单
|
|
||||||
### 2025.06.13 添加个股研报功能
|
|
||||||
### 2025.06.12 添加龙虎榜功能,新增行业排名分类
|
|
||||||
### 2025.05.30 优化股票分时图显示
|
|
||||||
### 2025.05.20 修复财联社电报获取问题
|
|
||||||
### 2025.05.16 优化资金趋势图表组件
|
|
||||||
### 2025.05.15 重构应用加载和数据初始化逻辑,添加股票资金趋势功能,资金趋势图表增加主力当日净流入数据并优化展示效果
|
|
||||||
### 2025.05.14 添加个股资金流向功能,排行榜增加股票行情K线图弹窗
|
|
||||||
### 2025.05.13 添加行业排名功能
|
|
||||||
### 2025.05.09 添加A股盘口数据解析和展示功能
|
|
||||||
### 2025.05.07 优化分时图的展示
|
|
||||||
### 2025.04.29 补全港股/美股基础数据,优化港股股价延迟问题,优化初始化逻辑
|
|
||||||
### 2025.04.25 市场资讯支持AI分析和总结:让AI帮你读市场!
|
|
||||||
### 2025.04.24 新增市场行情模块:即时掌握全球市场行情资讯/动态,从此再也不用偷摸去各大财经网站啦。go-stock一键帮你搞定!
|
### 2025.04.24 新增市场行情模块:即时掌握全球市场行情资讯/动态,从此再也不用偷摸去各大财经网站啦。go-stock一键帮你搞定!
|
||||||
### 2025.04.22 优化K线图展示,支持拉伸放大,看得更舒服啦!
|
### 2025.04.22 优化K线图展示,支持拉伸放大,看得更舒服啦!
|
||||||
### 2025.04.21 港股,美股K线数据获取优化
|
### 2025.04.21 港股,美股K线数据获取优化
|
||||||
@ -100,8 +78,6 @@
|
|||||||
|
|
||||||
## 🦄 重大更新
|
## 🦄 重大更新
|
||||||
### BIG NEWS !!! 重大更新!!!
|
### BIG NEWS !!! 重大更新!!!
|
||||||
- 2025.04.25 市场资讯支持AI分析和总结:让AI帮你读市场!
|
|
||||||

|
|
||||||
- 2025.04.24 新增市场行情模块:即时掌握全球市场行情资讯/动态,从此再也不用偷摸去各大财经网站啦。go-stock一键帮你搞定!
|
- 2025.04.24 新增市场行情模块:即时掌握全球市场行情资讯/动态,从此再也不用偷摸去各大财经网站啦。go-stock一键帮你搞定!
|
||||||

|

|
||||||

|

|
||||||
|
67
app.go
67
app.go
@ -139,22 +139,6 @@ func (a *App) CheckUpdate() {
|
|||||||
func (a *App) domReady(ctx context.Context) {
|
func (a *App) domReady(ctx context.Context) {
|
||||||
defer PanicHandler()
|
defer PanicHandler()
|
||||||
|
|
||||||
if stocksBin != nil && len(stocksBin) > 0 {
|
|
||||||
go runtime.EventsEmit(a.ctx, "loadingMsg", "检查A股基础信息...")
|
|
||||||
go initStockData(a.ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if stocksBinHK != nil && len(stocksBinHK) > 0 {
|
|
||||||
go runtime.EventsEmit(a.ctx, "loadingMsg", "检查港股基础信息...")
|
|
||||||
go initStockDataHK(a.ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if stocksBinUS != nil && len(stocksBinUS) > 0 {
|
|
||||||
go runtime.EventsEmit(a.ctx, "loadingMsg", "检查美股基础信息...")
|
|
||||||
go initStockDataUS(a.ctx)
|
|
||||||
}
|
|
||||||
updateBasicInfo()
|
|
||||||
|
|
||||||
// Add your action here
|
// Add your action here
|
||||||
//定时更新数据
|
//定时更新数据
|
||||||
config := data.NewSettingsApi(&data.Settings{}).GetConfig()
|
config := data.NewSettingsApi(&data.Settings{}).GetConfig()
|
||||||
@ -178,9 +162,6 @@ func (a *App) domReady(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
entryID, err := a.cron.AddFunc(fmt.Sprintf("@every %ds", interval+10), func() {
|
entryID, err := a.cron.AddFunc(fmt.Sprintf("@every %ds", interval+10), func() {
|
||||||
news := data.NewMarketNewsApi().GetNewTelegraph(30)
|
news := data.NewMarketNewsApi().GetNewTelegraph(30)
|
||||||
if config.EnablePushNews {
|
|
||||||
go a.NewsPush(news)
|
|
||||||
}
|
|
||||||
go runtime.EventsEmit(a.ctx, "newTelegraph", news)
|
go runtime.EventsEmit(a.ctx, "newTelegraph", news)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -191,9 +172,6 @@ func (a *App) domReady(ctx context.Context) {
|
|||||||
|
|
||||||
entryIDSina, err := a.cron.AddFunc(fmt.Sprintf("@every %ds", interval+10), func() {
|
entryIDSina, err := a.cron.AddFunc(fmt.Sprintf("@every %ds", interval+10), func() {
|
||||||
news := data.NewMarketNewsApi().GetSinaNews(30)
|
news := data.NewMarketNewsApi().GetSinaNews(30)
|
||||||
if config.EnablePushNews {
|
|
||||||
go a.NewsPush(news)
|
|
||||||
}
|
|
||||||
go runtime.EventsEmit(a.ctx, "newSinaNews", news)
|
go runtime.EventsEmit(a.ctx, "newSinaNews", news)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -298,15 +276,6 @@ func (a *App) domReady(ctx context.Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) NewsPush(news *[]models.Telegraph) {
|
|
||||||
for _, telegraph := range *news {
|
|
||||||
//if telegraph.IsRed {
|
|
||||||
go runtime.EventsEmit(a.ctx, "newsPush", telegraph)
|
|
||||||
go data.NewAlertWindowsApi("go-stock", telegraph.Source+" "+telegraph.Time, telegraph.Content, string(icon)).SendNotification()
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) AddCronTask(follow data.FollowedStock) func() {
|
func (a *App) AddCronTask(follow data.FollowedStock) func() {
|
||||||
return func() {
|
return func() {
|
||||||
go runtime.EventsEmit(a.ctx, "warnMsg", "开始自动分析"+follow.Name+"_"+follow.StockCode)
|
go runtime.EventsEmit(a.ctx, "warnMsg", "开始自动分析"+follow.Name+"_"+follow.StockCode)
|
||||||
@ -1096,17 +1065,6 @@ func (a *App) RemoveGroup(groupId int) string {
|
|||||||
func (a *App) GetStockKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
func (a *App) GetStockKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
||||||
return data.NewStockDataApi().GetHK_KLineData(stockCode, "day", days)
|
return data.NewStockDataApi().GetHK_KLineData(stockCode, "day", days)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetStockMinutePriceLineData(stockCode, stockName string) map[string]any {
|
|
||||||
res := make(map[string]any, 4)
|
|
||||||
priceData, date := data.NewStockDataApi().GetStockMinutePriceData(stockCode)
|
|
||||||
res["priceData"] = priceData
|
|
||||||
res["date"] = date
|
|
||||||
res["stockName"] = stockName
|
|
||||||
res["stockCode"] = stockCode
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) GetStockCommonKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
func (a *App) GetStockCommonKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
||||||
return data.NewStockDataApi().GetCommonKLineData(stockCode, "day", days)
|
return data.NewStockDataApi().GetCommonKLineData(stockCode, "day", days)
|
||||||
}
|
}
|
||||||
@ -1116,13 +1074,6 @@ func (a *App) GetTelegraphList(source string) *[]*models.Telegraph {
|
|||||||
return telegraphs
|
return telegraphs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) ReFleshTelegraphList(source string) *[]*models.Telegraph {
|
|
||||||
data.NewMarketNewsApi().GetNewTelegraph(30)
|
|
||||||
data.NewMarketNewsApi().GetSinaNews(30)
|
|
||||||
telegraphs := data.NewMarketNewsApi().GetTelegraphList(source)
|
|
||||||
return telegraphs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) GlobalStockIndexes() map[string]any {
|
func (a *App) GlobalStockIndexes() map[string]any {
|
||||||
return data.NewMarketNewsApi().GlobalStockIndexes(30)
|
return data.NewMarketNewsApi().GlobalStockIndexes(30)
|
||||||
}
|
}
|
||||||
@ -1134,21 +1085,3 @@ func (a *App) SummaryStockNews(question string, sysPromptId *int) {
|
|||||||
}
|
}
|
||||||
runtime.EventsEmit(a.ctx, "summaryStockNews", "DONE")
|
runtime.EventsEmit(a.ctx, "summaryStockNews", "DONE")
|
||||||
}
|
}
|
||||||
func (a *App) GetIndustryRank(sort string, cnt int) []any {
|
|
||||||
res := data.NewMarketNewsApi().GetIndustryRank(sort, cnt)
|
|
||||||
return res["data"].([]any)
|
|
||||||
}
|
|
||||||
func (a *App) GetIndustryMoneyRankSina(fenlei, sort string) []map[string]any {
|
|
||||||
res := data.NewMarketNewsApi().GetIndustryMoneyRankSina(fenlei, sort)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
func (a *App) GetMoneyRankSina(sort string) []map[string]any {
|
|
||||||
res := data.NewMarketNewsApi().GetMoneyRankSina(sort)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) GetStockMoneyTrendByDay(stockCode string, days int) []map[string]any {
|
|
||||||
res := data.NewMarketNewsApi().GetStockMoneyTrendByDay(stockCode, days)
|
|
||||||
slice.Reverse(res)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go-stock/backend/data"
|
|
||||||
"go-stock/backend/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// @Author spark
|
|
||||||
// @Date 2025/6/8 20:45
|
|
||||||
// @Desc
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func (a *App) LongTigerRank(date string) *[]models.LongTigerRankData {
|
|
||||||
return data.NewMarketNewsApi().LongTiger(date)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) StockResearchReport(stockCode string) []any {
|
|
||||||
return data.NewMarketNewsApi().StockResearchReport(stockCode, 7)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
@ -1,17 +1,13 @@
|
|||||||
package data
|
package data
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/coocood/freecache"
|
|
||||||
"github.com/duke-git/lancet/v2/convertor"
|
|
||||||
"github.com/duke-git/lancet/v2/strutil"
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
"go-stock/backend/db"
|
"go-stock/backend/db"
|
||||||
"go-stock/backend/logger"
|
"go-stock/backend/logger"
|
||||||
"go-stock/backend/models"
|
"go-stock/backend/models"
|
||||||
@ -41,7 +37,7 @@ func (m MarketNewsApi) GetNewTelegraph(crawlTimeOut int64) *[]models.Telegraph {
|
|||||||
//logger.SugaredLogger.Info(string(response.Body()))
|
//logger.SugaredLogger.Info(string(response.Body()))
|
||||||
document, _ := goquery.NewDocumentFromReader(strings.NewReader(string(response.Body())))
|
document, _ := goquery.NewDocumentFromReader(strings.NewReader(string(response.Body())))
|
||||||
|
|
||||||
document.Find(".telegraph-content-box").Each(func(i int, selection *goquery.Selection) {
|
document.Find(".telegraph-list").Each(func(i int, selection *goquery.Selection) {
|
||||||
//logger.SugaredLogger.Info(selection.Text())
|
//logger.SugaredLogger.Info(selection.Text())
|
||||||
telegraph := models.Telegraph{Source: "财联社电报"}
|
telegraph := models.Telegraph{Source: "财联社电报"}
|
||||||
spans := selection.Find("div.telegraph-content-box span")
|
spans := selection.Find("div.telegraph-content-box span")
|
||||||
@ -73,7 +69,6 @@ func (m MarketNewsApi) GetNewTelegraph(crawlTimeOut int64) *[]models.Telegraph {
|
|||||||
|
|
||||||
//telegraph = append(telegraph, ReplaceSensitiveWords(selection.Text()))
|
//telegraph = append(telegraph, ReplaceSensitiveWords(selection.Text()))
|
||||||
if telegraph.Content != "" {
|
if telegraph.Content != "" {
|
||||||
telegraph.SentimentResult = AnalyzeSentiment(telegraph.Content).Description
|
|
||||||
cnt := int64(0)
|
cnt := int64(0)
|
||||||
db.Dao.Model(telegraph).Where("time=? and source=?", telegraph.Time, telegraph.Source).Count(&cnt)
|
db.Dao.Model(telegraph).Where("time=? and source=?", telegraph.Time, telegraph.Source).Count(&cnt)
|
||||||
if cnt == 0 {
|
if cnt == 0 {
|
||||||
@ -143,7 +138,8 @@ 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").
|
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))
|
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 := string(response.Body())
|
||||||
js = strutil.ReplaceWithMap(js, map[string]string{
|
js = strutil.ReplaceWithMap(js,
|
||||||
|
map[string]string{
|
||||||
"try{callback(": "var data=",
|
"try{callback(": "var data=",
|
||||||
");}catch(e){};": ";",
|
");}catch(e){};": ";",
|
||||||
})
|
})
|
||||||
@ -193,7 +189,6 @@ func (m MarketNewsApi) GetSinaNews(crawlTimeOut uint) *[]models.Telegraph {
|
|||||||
logger.SugaredLogger.Infof("telegraph.SubjectTags:%v %s", telegraph.SubjectTags, telegraph.Content)
|
logger.SugaredLogger.Infof("telegraph.SubjectTags:%v %s", telegraph.SubjectTags, telegraph.Content)
|
||||||
|
|
||||||
if telegraph.Content != "" {
|
if telegraph.Content != "" {
|
||||||
telegraph.SentimentResult = AnalyzeSentiment(telegraph.Content).Description
|
|
||||||
cnt := int64(0)
|
cnt := int64(0)
|
||||||
db.Dao.Model(telegraph).Where("time=? and source=?", telegraph.Time, telegraph.Source).Count(&cnt)
|
db.Dao.Model(telegraph).Where("time=? and source=?", telegraph.Time, telegraph.Source).Count(&cnt)
|
||||||
if cnt == 0 {
|
if cnt == 0 {
|
||||||
@ -229,475 +224,3 @@ func (m MarketNewsApi) GlobalStockIndexes(crawlTimeOut uint) map[string]any {
|
|||||||
json.Unmarshal([]byte(js), &res)
|
json.Unmarshal([]byte(js), &res)
|
||||||
return res["data"].(map[string]any)
|
return res["data"].(map[string]any)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MarketNewsApi) GetIndustryRank(sort string, cnt int) map[string]any {
|
|
||||||
|
|
||||||
url := fmt.Sprintf("https://proxy.finance.qq.com/ifzqgtimg/appstock/app/mktHs/rank?l=%d&p=1&t=01/averatio&ordertype=&o=%s", cnt, sort)
|
|
||||||
response, _ := resty.New().SetTimeout(time.Duration(5)*time.Second).R().
|
|
||||||
SetHeader("Referer", "https://stockapp.finance.qq.com/").
|
|
||||||
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)
|
|
||||||
js := string(response.Body())
|
|
||||||
res := make(map[string]any)
|
|
||||||
json.Unmarshal([]byte(js), &res)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m MarketNewsApi) GetIndustryMoneyRankSina(fenlei, sort string) []map[string]any {
|
|
||||||
url := fmt.Sprintf("https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/MoneyFlow.ssl_bkzj_bk?page=1&num=20&sort=%s&asc=0&fenlei=%s", sort, fenlei)
|
|
||||||
|
|
||||||
response, _ := resty.New().SetTimeout(time.Duration(5)*time.Second).R().
|
|
||||||
SetHeader("Host", "vip.stock.finance.sina.com.cn").
|
|
||||||
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)
|
|
||||||
js := string(response.Body())
|
|
||||||
res := &[]map[string]any{}
|
|
||||||
err := json.Unmarshal([]byte(js), &res)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Error(err)
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m MarketNewsApi) GetMoneyRankSina(sort string) []map[string]any {
|
|
||||||
if sort == "" {
|
|
||||||
sort = "netamount"
|
|
||||||
}
|
|
||||||
url := fmt.Sprintf("https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/MoneyFlow.ssl_bkzj_ssggzj?page=1&num=20&sort=%s&asc=0&bankuai=&shichang=", sort)
|
|
||||||
response, _ := resty.New().SetTimeout(time.Duration(5)*time.Second).R().
|
|
||||||
SetHeader("Host", "vip.stock.finance.sina.com.cn").
|
|
||||||
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)
|
|
||||||
js := string(response.Body())
|
|
||||||
res := &[]map[string]any{}
|
|
||||||
err := json.Unmarshal([]byte(js), &res)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Error(err)
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m MarketNewsApi) GetStockMoneyTrendByDay(stockCode string, days int) []map[string]any {
|
|
||||||
url := fmt.Sprintf("http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/MoneyFlow.ssl_qsfx_zjlrqs?page=1&num=%d&sort=opendate&asc=0&daima=%s", days, stockCode)
|
|
||||||
|
|
||||||
response, _ := resty.New().SetTimeout(time.Duration(5)*time.Second).R().
|
|
||||||
SetHeader("Host", "vip.stock.finance.sina.com.cn").
|
|
||||||
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)
|
|
||||||
js := string(response.Body())
|
|
||||||
res := &[]map[string]any{}
|
|
||||||
err := json.Unmarshal([]byte(js), &res)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Error(err)
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
return *res
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m MarketNewsApi) TopStocksRankingList(date string) {
|
|
||||||
url := fmt.Sprintf("http://vip.stock.finance.sina.com.cn/q/go.php/vInvestConsult/kind/lhb/index.phtml?tradedate=%s", date)
|
|
||||||
response, _ := resty.New().SetTimeout(time.Duration(5)*time.Second).R().
|
|
||||||
SetHeader("Host", "vip.stock.finance.sina.com.cn").
|
|
||||||
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())
|
|
||||||
//logger.SugaredLogger.Infof("html:%s", html)
|
|
||||||
document, err := goquery.NewDocumentFromReader(bytes.NewReader(html))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
document.Find("table.list_table").Each(func(i int, s *goquery.Selection) {
|
|
||||||
title := strutil.Trim(s.Find("tr:first-child").First().Text())
|
|
||||||
logger.SugaredLogger.Infof("title:%s", title)
|
|
||||||
s.Find("tr:not(:first-child)").Each(func(i int, s *goquery.Selection) {
|
|
||||||
logger.SugaredLogger.Infof("s:%s", strutil.RemoveNonPrintable(s.Text()))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m MarketNewsApi) LongTiger(date string) *[]models.LongTigerRankData {
|
|
||||||
ranks := &[]models.LongTigerRankData{}
|
|
||||||
url := "https://datacenter-web.eastmoney.com/api/data/v1/get"
|
|
||||||
logger.SugaredLogger.Infof("url:%s", url)
|
|
||||||
params := make(map[string]string)
|
|
||||||
params["callback"] = "callback"
|
|
||||||
params["sortColumns"] = "TURNOVERRATE,TRADE_DATE,SECURITY_CODE"
|
|
||||||
params["sortTypes"] = "-1,-1,1"
|
|
||||||
params["pageSize"] = "500"
|
|
||||||
params["pageNumber"] = "1"
|
|
||||||
params["reportName"] = "RPT_DAILYBILLBOARD_DETAILSNEW"
|
|
||||||
params["columns"] = "SECURITY_CODE,SECUCODE,SECURITY_NAME_ABBR,TRADE_DATE,EXPLAIN,CLOSE_PRICE,CHANGE_RATE,BILLBOARD_NET_AMT,BILLBOARD_BUY_AMT,BILLBOARD_SELL_AMT,BILLBOARD_DEAL_AMT,ACCUM_AMOUNT,DEAL_NET_RATIO,DEAL_AMOUNT_RATIO,TURNOVERRATE,FREE_MARKET_CAP,EXPLANATION,D1_CLOSE_ADJCHRATE,D2_CLOSE_ADJCHRATE,D5_CLOSE_ADJCHRATE,D10_CLOSE_ADJCHRATE,SECURITY_TYPE_CODE"
|
|
||||||
params["source"] = "WEB"
|
|
||||||
params["client"] = "WEB"
|
|
||||||
params["filter"] = fmt.Sprintf("(TRADE_DATE<='%s')(TRADE_DATE>='%s')", date, date)
|
|
||||||
resp, err := resty.New().SetTimeout(time.Duration(15)*time.Second).R().
|
|
||||||
SetHeader("Host", "datacenter-web.eastmoney.com").
|
|
||||||
SetHeader("Referer", "https://data.eastmoney.com/stock/tradedetail.html").
|
|
||||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
|
||||||
SetQueryParams(params).
|
|
||||||
Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return ranks
|
|
||||||
}
|
|
||||||
js := string(resp.Body())
|
|
||||||
logger.SugaredLogger.Infof("resp:%s", js)
|
|
||||||
|
|
||||||
js = strutil.ReplaceWithMap(js, map[string]string{
|
|
||||||
"callback(": "var data=",
|
|
||||||
");": ";",
|
|
||||||
})
|
|
||||||
//logger.SugaredLogger.Info(js)
|
|
||||||
vm := otto.New()
|
|
||||||
_, err = vm.Run(js)
|
|
||||||
_, err = vm.Run("var data = JSON.stringify(data);")
|
|
||||||
value, err := vm.Get("data")
|
|
||||||
logger.SugaredLogger.Infof("resp-json:%s", value.String())
|
|
||||||
data := gjson.Get(value.String(), "result.data")
|
|
||||||
logger.SugaredLogger.Infof("resp:%v", data)
|
|
||||||
err = json.Unmarshal([]byte(data.String()), ranks)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Error(err)
|
|
||||||
return ranks
|
|
||||||
}
|
|
||||||
for _, rankData := range *ranks {
|
|
||||||
temp := &models.LongTigerRankData{}
|
|
||||||
db.Dao.Model(temp).Where(&models.LongTigerRankData{
|
|
||||||
TRADEDATE: rankData.TRADEDATE,
|
|
||||||
SECUCODE: rankData.SECUCODE,
|
|
||||||
}).First(temp)
|
|
||||||
if temp.SECURITYTYPECODE == "" {
|
|
||||||
db.Dao.Model(temp).Create(&rankData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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")
|
|
||||||
if strutil.ContainsAny(stockCode, []string{"."}) {
|
|
||||||
stockCode = strings.Split(stockCode, ".")[0]
|
|
||||||
beginDate = time.Now().Add(-time.Duration(days) * 365 * time.Hour).Format("2006-01-02")
|
|
||||||
} else {
|
|
||||||
stockCode = strutil.ReplaceWithMap(stockCode, map[string]string{
|
|
||||||
"sh": "",
|
|
||||||
"sz": "",
|
|
||||||
"gb_": "",
|
|
||||||
"us": "",
|
|
||||||
"us_": "",
|
|
||||||
})
|
|
||||||
beginDate = time.Now().Add(-time.Duration(days) * 365 * time.Hour).Format("2006-01-02")
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.SugaredLogger.Infof("StockResearchReport-stockCode:%s", stockCode)
|
|
||||||
|
|
||||||
type Req struct {
|
|
||||||
BeginTime string `json:"beginTime"`
|
|
||||||
EndTime string `json:"endTime"`
|
|
||||||
IndustryCode string `json:"industryCode"`
|
|
||||||
RatingChange string `json:"ratingChange"`
|
|
||||||
Rating string `json:"rating"`
|
|
||||||
OrgCode interface{} `json:"orgCode"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
Rcode string `json:"rcode"`
|
|
||||||
PageSize int `json:"pageSize"`
|
|
||||||
PageNo int `json:"pageNo"`
|
|
||||||
P int `json:"p"`
|
|
||||||
PageNum int `json:"pageNum"`
|
|
||||||
PageNumber int `json:"pageNumber"`
|
|
||||||
}
|
|
||||||
|
|
||||||
url := "https://reportapi.eastmoney.com/report/list2"
|
|
||||||
|
|
||||||
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").
|
|
||||||
SetBody(&Req{
|
|
||||||
Code: stockCode,
|
|
||||||
IndustryCode: "*",
|
|
||||||
BeginTime: beginDate,
|
|
||||||
EndTime: endDate,
|
|
||||||
PageNo: 1,
|
|
||||||
PageSize: 50,
|
|
||||||
P: 1,
|
|
||||||
PageNum: 1,
|
|
||||||
PageNumber: 1,
|
|
||||||
}).Post(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) StockNotice(stock_list string) []any {
|
|
||||||
var stockCodes []string
|
|
||||||
for _, stockCode := range strings.Split(stock_list, ",") {
|
|
||||||
if strutil.ContainsAny(stockCode, []string{"."}) {
|
|
||||||
stockCode = strings.Split(stockCode, ".")[0]
|
|
||||||
stockCodes = append(stockCodes, stockCode)
|
|
||||||
} else {
|
|
||||||
stockCode = strutil.ReplaceWithMap(stockCode, map[string]string{
|
|
||||||
"sh": "",
|
|
||||||
"sz": "",
|
|
||||||
"gb_": "",
|
|
||||||
"us": "",
|
|
||||||
"us_": "",
|
|
||||||
})
|
|
||||||
stockCodes = append(stockCodes, stockCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
url := "https://np-anotice-stock.eastmoney.com/api/security/ann?page_size=50&page_index=1&ann_type=SHA%2CCYB%2CSZA%2CBJA%2CINV&client_source=web&f_node=0&stock_list=" + strings.Join(stockCodes, ",")
|
|
||||||
resp, err := resty.New().SetTimeout(time.Duration(15)*time.Second).R().
|
|
||||||
SetHeader("Host", "np-anotice-stock.eastmoney.com").
|
|
||||||
SetHeader("Referer", "https://data.eastmoney.com/notices/hsa/5.html").
|
|
||||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
|
||||||
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"].(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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m MarketNewsApi) TradingViewNews() *[]models.TVNews {
|
|
||||||
TVNews := &[]models.TVNews{}
|
|
||||||
url := "https://news-mediator.tradingview.com/news-flow/v2/news?filter=lang:zh-Hans&filter=provider:panews,reuters&client=screener&streaming=false"
|
|
||||||
resp, err := resty.New().SetProxy("http://127.0.0.1:10809").SetTimeout(time.Duration(30)*time.Second).R().
|
|
||||||
SetHeader("Host", "news-mediator.tradingview.com").
|
|
||||||
SetHeader("Origin", "https://cn.tradingview.com").
|
|
||||||
SetHeader("Referer", "https://cn.tradingview.com/").
|
|
||||||
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("TradingViewNews err:%s", err.Error())
|
|
||||||
return TVNews
|
|
||||||
}
|
|
||||||
respMap := map[string]any{}
|
|
||||||
err = json.Unmarshal(resp.Body(), &respMap)
|
|
||||||
if err != nil {
|
|
||||||
return TVNews
|
|
||||||
}
|
|
||||||
items, err := json.Marshal(respMap["items"])
|
|
||||||
if err != nil {
|
|
||||||
return 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)
|
|
||||||
}
|
|
||||||
|
@ -2,7 +2,6 @@ package data
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/coocood/freecache"
|
|
||||||
"go-stock/backend/db"
|
"go-stock/backend/db"
|
||||||
"go-stock/backend/logger"
|
"go-stock/backend/logger"
|
||||||
"testing"
|
"testing"
|
||||||
@ -28,126 +27,3 @@ func TestGlobalStockIndexes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
logger.SugaredLogger.Debugf("resp: %+v", string(bytes))
|
logger.SugaredLogger.Debugf("resp: %+v", string(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetIndustryRank(t *testing.T) {
|
|
||||||
res := NewMarketNewsApi().GetIndustryRank("0", 10)
|
|
||||||
for s, a := range res["data"].([]any) {
|
|
||||||
logger.SugaredLogger.Debugf("key: %+v, value: %+v", s, a)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestGetIndustryMoneyRankSina(t *testing.T) {
|
|
||||||
res := NewMarketNewsApi().GetIndustryMoneyRankSina("0", "netamount")
|
|
||||||
for i, re := range res {
|
|
||||||
logger.SugaredLogger.Debugf("key: %+v, value: %+v", i, re)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestGetMoneyRankSina(t *testing.T) {
|
|
||||||
res := NewMarketNewsApi().GetMoneyRankSina("r3_net")
|
|
||||||
for i, re := range res {
|
|
||||||
logger.SugaredLogger.Debugf("key: %+v, value: %+v", i, re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetStockMoneyTrendByDay(t *testing.T) {
|
|
||||||
res := NewMarketNewsApi().GetStockMoneyTrendByDay("sh600438", 360)
|
|
||||||
for i, re := range res {
|
|
||||||
logger.SugaredLogger.Debugf("key: %+v, value: %+v", i, re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestTopStocksRankingList(t *testing.T) {
|
|
||||||
NewMarketNewsApi().TopStocksRankingList("2025-05-19")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLongTiger(t *testing.T) {
|
|
||||||
db.Init("../../data/stock.db")
|
|
||||||
|
|
||||||
NewMarketNewsApi().LongTiger("2025-06-08")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStockResearchReport(t *testing.T) {
|
|
||||||
db.Init("../../data/stock.db")
|
|
||||||
resp := NewMarketNewsApi().StockResearchReport("600584.sh", 7)
|
|
||||||
for _, a := range resp {
|
|
||||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
for _, a := range resp {
|
|
||||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEMDictCode(t *testing.T) {
|
|
||||||
db.Init("../../data/stock.db")
|
|
||||||
resp := NewMarketNewsApi().EMDictCode("016", freecache.NewCache(100))
|
|
||||||
for _, a := range resp {
|
|
||||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTradingViewNews(t *testing.T) {
|
|
||||||
db.Init("../../data/stock.db")
|
|
||||||
resp := NewMarketNewsApi().TradingViewNews()
|
|
||||||
for _, a := range *resp {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -161,7 +161,7 @@ func (o OpenAi) NewSummaryStockNewsStream(userQuestion string, sysPromptId *int)
|
|||||||
}()
|
}()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
news := NewMarketNewsApi().GetNewsList("", 100)
|
news := NewMarketNewsApi().GetNewsList("财联社电报", 100)
|
||||||
messageText := strings.Builder{}
|
messageText := strings.Builder{}
|
||||||
for _, telegraph := range *news {
|
for _, telegraph := range *news {
|
||||||
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
|
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
|
||||||
@ -849,6 +849,6 @@ func (o OpenAi) SaveAIResponseResult(stockCode, stockName, result, chatId, quest
|
|||||||
|
|
||||||
func (o OpenAi) GetAIResponseResult(stock string) *models.AIResponseResult {
|
func (o OpenAi) GetAIResponseResult(stock string) *models.AIResponseResult {
|
||||||
var result models.AIResponseResult
|
var result models.AIResponseResult
|
||||||
db.Dao.Where("stock_code = ?", stock).Order("id desc").Limit(1).Find(&result)
|
db.Dao.Where("stock_code = ?", stock).Order("id desc").Limit(1).First(&result)
|
||||||
return &result
|
return &result
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,11 @@ func TestNewDeepSeekOpenAiConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTopNewsList(t *testing.T) {
|
func TestGetTopNewsList(t *testing.T) {
|
||||||
news := GetTopNewsList(30)
|
GetTopNewsList(30)
|
||||||
t.Log(news)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSearchGuShiTongStockInfo(t *testing.T) {
|
func TestSearchGuShiTongStockInfo(t *testing.T) {
|
||||||
db.Init("../../data/stock.db")
|
//db.Init("../../data/stock.db")
|
||||||
SearchGuShiTongStockInfo("hk01810", 60)
|
SearchGuShiTongStockInfo("hk01810", 60)
|
||||||
SearchGuShiTongStockInfo("sh600745", 60)
|
SearchGuShiTongStockInfo("sh600745", 60)
|
||||||
SearchGuShiTongStockInfo("gb_goog", 60)
|
SearchGuShiTongStockInfo("gb_goog", 60)
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
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)
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
@ -34,7 +34,6 @@ type Settings struct {
|
|||||||
DarkTheme bool `json:"darkTheme"`
|
DarkTheme bool `json:"darkTheme"`
|
||||||
BrowserPoolSize int `json:"browserPoolSize"`
|
BrowserPoolSize int `json:"browserPoolSize"`
|
||||||
EnableFund bool `json:"enableFund"`
|
EnableFund bool `json:"enableFund"`
|
||||||
EnablePushNews bool `json:"enablePushNews"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (receiver Settings) TableName() string {
|
func (receiver Settings) TableName() string {
|
||||||
@ -79,7 +78,6 @@ func (s SettingsApi) UpdateConfig() string {
|
|||||||
"enable_news": s.Config.EnableNews,
|
"enable_news": s.Config.EnableNews,
|
||||||
"dark_theme": s.Config.DarkTheme,
|
"dark_theme": s.Config.DarkTheme,
|
||||||
"enable_fund": s.Config.EnableFund,
|
"enable_fund": s.Config.EnableFund,
|
||||||
"enable_push_news": s.Config.EnablePushNews,
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
logger.SugaredLogger.Infof("未找到配置,创建默认配置:%+v", s.Config)
|
logger.SugaredLogger.Infof("未找到配置,创建默认配置:%+v", s.Config)
|
||||||
@ -107,7 +105,6 @@ func (s SettingsApi) UpdateConfig() string {
|
|||||||
EnableNews: s.Config.EnableNews,
|
EnableNews: s.Config.EnableNews,
|
||||||
DarkTheme: s.Config.DarkTheme,
|
DarkTheme: s.Config.DarkTheme,
|
||||||
EnableFund: s.Config.EnableFund,
|
EnableFund: s.Config.EnableFund,
|
||||||
EnablePushNews: s.Config.EnablePushNews,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return "保存成功!"
|
return "保存成功!"
|
||||||
|
File diff suppressed because one or more lines are too long
@ -8,6 +8,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/chromedp/chromedp"
|
"github.com/chromedp/chromedp"
|
||||||
@ -15,7 +16,6 @@ import (
|
|||||||
"github.com/duke-git/lancet/v2/slice"
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
"github.com/duke-git/lancet/v2/strutil"
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"github.com/robertkrimen/otto"
|
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"go-stock/backend/db"
|
"go-stock/backend/db"
|
||||||
"go-stock/backend/logger"
|
"go-stock/backend/logger"
|
||||||
@ -26,14 +26,11 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/plugin/soft_delete"
|
"gorm.io/plugin/soft_delete"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const sinaStockUrl = "http://hq.sinajs.cn/rn=%d&list=%s"
|
const sinaStockUrl = "http://hq.sinajs.cn/rn=%d&list=%s"
|
||||||
const txStockUrl = "http://qt.gtimg.cn/?_=%d&q=%s"
|
|
||||||
|
|
||||||
const tushareApiUrl = "http://api.tushare.pro"
|
const tushareApiUrl = "http://api.tushare.pro"
|
||||||
|
|
||||||
type StockDataApi struct {
|
type StockDataApi struct {
|
||||||
@ -248,7 +245,7 @@ func (receiver StockDataApi) GetIndexBasic() {
|
|||||||
func (receiver StockDataApi) GetStockBaseInfo() {
|
func (receiver StockDataApi) GetStockBaseInfo() {
|
||||||
res := &TushareStockBasicResponse{}
|
res := &TushareStockBasicResponse{}
|
||||||
fields := "ts_code,symbol,name,area,industry,cnspell,market,list_date,act_name,act_ent_type,fullname,exchange,list_status,curr_type,enname,delist_date,is_hs"
|
fields := "ts_code,symbol,name,area,industry,cnspell,market,list_date,act_name,act_ent_type,fullname,exchange,list_status,curr_type,enname,delist_date,is_hs"
|
||||||
resp, err := receiver.client.R().
|
_, err := receiver.client.R().
|
||||||
SetHeader("content-type", "application/json").
|
SetHeader("content-type", "application/json").
|
||||||
SetBody(&TushareRequest{
|
SetBody(&TushareRequest{
|
||||||
ApiName: "stock_basic",
|
ApiName: "stock_basic",
|
||||||
@ -259,7 +256,8 @@ func (receiver StockDataApi) GetStockBaseInfo() {
|
|||||||
SetResult(res).
|
SetResult(res).
|
||||||
Post(tushareApiUrl)
|
Post(tushareApiUrl)
|
||||||
//logger.SugaredLogger.Infof("GetStockBaseInfo %s", string(resp.Body()))
|
//logger.SugaredLogger.Infof("GetStockBaseInfo %s", string(resp.Body()))
|
||||||
ioutil.WriteFile("stock_basic.json", resp.Body(), 0666)
|
//resp.Body()写入文件
|
||||||
|
//ioutil.WriteFile("stock_basic.json", resp.Body(), 0666)
|
||||||
//logger.SugaredLogger.Infof("GetStockBaseInfo %+v", res)
|
//logger.SugaredLogger.Infof("GetStockBaseInfo %+v", res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.SugaredLogger.Error(err.Error())
|
logger.SugaredLogger.Error(err.Error())
|
||||||
@ -292,58 +290,8 @@ func (receiver StockDataApi) GetStockBaseInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (receiver StockDataApi) GetStockCodeRealTimeData(StockCodes ...string) (*[]StockInfo, error) {
|
func (receiver StockDataApi) GetStockCodeRealTimeData(StockCodes ...string) (*[]StockInfo, error) {
|
||||||
stockInfos := make([]StockInfo, 0)
|
|
||||||
|
|
||||||
hkcodes := slice.Filter(StockCodes, func(i int, s string) bool {
|
codes := slice.JoinFunc(StockCodes, ",", func(s string) string {
|
||||||
return strutil.HasPrefixAny(s, []string{"hk", "HK", "sh", "sz"})
|
|
||||||
})
|
|
||||||
|
|
||||||
if hkcodes != nil && len(hkcodes) > 0 {
|
|
||||||
hkcodesStr := slice.JoinFunc(hkcodes, ",", func(s string) string {
|
|
||||||
if strutil.HasPrefixAny(s, []string{"hk", "HK"}) {
|
|
||||||
return "r_" + strings.ToLower(s)
|
|
||||||
} else {
|
|
||||||
return strings.ToLower(s)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
url := fmt.Sprintf(txStockUrl, time.Now().Unix(), hkcodesStr)
|
|
||||||
resp, err := receiver.client.R().
|
|
||||||
SetHeader("Host", "qt.gtimg.cn").
|
|
||||||
SetHeader("Referer", "https://gu.qq.com/").
|
|
||||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
|
|
||||||
Get(url)
|
|
||||||
logger.SugaredLogger.Infof("GetStockCodeRealTimeData %s", url)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Error(err.Error())
|
|
||||||
return &[]StockInfo{}, err
|
|
||||||
}
|
|
||||||
str := GB18030ToUTF8(resp.Body())
|
|
||||||
dataStr := strutil.SplitAndTrim(strings.Trim(str, "\n"), ";")
|
|
||||||
|
|
||||||
for _, data := range dataStr {
|
|
||||||
stockData, err := ParseTxStockData(data)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Error(err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
stockInfos = append(stockInfos, *stockData)
|
|
||||||
go func() {
|
|
||||||
var count int64
|
|
||||||
db.Dao.Model(&StockInfo{}).Where("code = ?", stockData.Code).Count(&count)
|
|
||||||
if count == 0 {
|
|
||||||
db.Dao.Model(&StockInfo{}).Create(stockData)
|
|
||||||
} else {
|
|
||||||
db.Dao.Model(&StockInfo{}).Where("code = ?", stockData.Code).Updates(stockData)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
szzsusCodes := slice.Filter(StockCodes, func(i int, s string) bool {
|
|
||||||
return !strutil.HasPrefixAny(s, []string{"hk", "HK", "sh", "sz"})
|
|
||||||
})
|
|
||||||
|
|
||||||
codes := slice.JoinFunc(szzsusCodes, ",", func(s string) string {
|
|
||||||
if strings.HasPrefix(s, "us") {
|
if strings.HasPrefix(s, "us") {
|
||||||
s = strings.Replace(s, "us", "gb_", 1)
|
s = strings.Replace(s, "us", "gb_", 1)
|
||||||
}
|
}
|
||||||
@ -365,9 +313,12 @@ func (receiver StockDataApi) GetStockCodeRealTimeData(StockCodes ...string) (*[]
|
|||||||
return &[]StockInfo{}, err
|
return &[]StockInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stockInfos := make([]StockInfo, 0)
|
||||||
str := GB18030ToUTF8(resp.Body())
|
str := GB18030ToUTF8(resp.Body())
|
||||||
dataStr := strutil.SplitEx(str, "\n", true)
|
dataStr := strutil.SplitEx(str, "\n", true)
|
||||||
|
if len(dataStr) == 0 {
|
||||||
|
return &[]StockInfo{}, errors.New("获取股票信息失败,请检查股票代码是否正确")
|
||||||
|
}
|
||||||
for _, data := range dataStr {
|
for _, data := range dataStr {
|
||||||
//logger.SugaredLogger.Info(data)
|
//logger.SugaredLogger.Info(data)
|
||||||
stockData, err := ParseFullSingleStockData(data)
|
stockData, err := ParseFullSingleStockData(data)
|
||||||
@ -400,20 +351,7 @@ func (receiver StockDataApi) Follow(stockCode string) string {
|
|||||||
logger.SugaredLogger.Error(err)
|
logger.SugaredLogger.Error(err)
|
||||||
return "关注失败"
|
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)
|
maxSort := int64(0)
|
||||||
db.Dao.Model(&FollowedStock{}).Raw("select max(sort) as sort from followed_stock").Scan(&maxSort)
|
db.Dao.Model(&FollowedStock{}).Raw("select max(sort) as sort from followed_stock").Scan(&maxSort)
|
||||||
|
|
||||||
@ -476,64 +414,15 @@ func (receiver StockDataApi) SetAlarmChangePercent(val, alarmPrice float64, stoc
|
|||||||
return "设置成功"
|
return "设置成功"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (receiver StockDataApi) SetStockSort(newSort int64, stockCode string) {
|
func (receiver StockDataApi) SetStockSort(sort int64, stockCode string) {
|
||||||
//if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
||||||
// stockCode = strings.ToLower(stockCode)
|
stockCode = strings.ToLower(stockCode)
|
||||||
// stockCode = strings.Replace(stockCode, "gb_", "us", 1)
|
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
|
||||||
oldSort := currentStock.Sort
|
if err != nil {
|
||||||
|
logger.SugaredLogger.Error(err.Error())
|
||||||
// 如果排序值没有变化,直接返回
|
|
||||||
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) {
|
func (receiver StockDataApi) SetStockAICron(cron string, stockCode string) {
|
||||||
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
||||||
@ -619,146 +508,6 @@ func GB18030ToUTF8(bs []byte) string {
|
|||||||
return string(d)
|
return string(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxStockData(data string) (*StockInfo, error) {
|
|
||||||
//v_r_hk09660="100~地平线机器人-W~09660~6.240~5.690~5.800~192659034.0~0~0~6.240~0~0~0~0~0~0~0~0~0~6.240~0~0~0~0~0~0~0~0~0~192659034.0~2025/04/29
|
|
||||||
//13:41:04~0.550~9.67~6.450~5.710~6.240~192659034.0~1180471843.140~0~32.51~~0~0~13.01~691.1364~823.6983~HORIZONROBOT-W~0.00~10.380~3.320~1.07~-16.03~0~0~0~0~0~32.51~6.40~1.74~600~73.33~17.96~GP~19.70~11.51~-0.95~-18.54~44.44~13200293682.00~11075904412.00~32.51~0.000~6.127~56.39~HKD~1~30";
|
|
||||||
//v_sz002241="51~歌尔股份~002241~22.26~22.27~0.00~0~0~0~22.26~1004~0.00~0~0.00~0~0.00~0~0.00~0~22.26~1004~0.00~558~0.00~0~0.00~0~0.00~0~~20250509092233~-0.01~-0.04~0.00~0.00~22.26/0/0~0~0~0.00~28.21~~0.00~0.00~0.00~686.46~777.09~2.31~24.50~20.04~0.00~-558~0.00~41.44~29.16~~~1.24~0.0000~0.0000~0~
|
|
||||||
//~GP-A~-13.75~6.76~1.09~8.18~3.39~30.63~15.70~6.87~17.47~-23.95~3083811231~3490989083~-21.75~12.02~3083811231~~~39.36~-0.04~~CNY~0~~0.00~0";
|
|
||||||
|
|
||||||
datas := strutil.SplitAndTrim(data, "=", "\"")
|
|
||||||
if len(datas) < 2 {
|
|
||||||
return nil, fmt.Errorf("invalid data format")
|
|
||||||
}
|
|
||||||
var result map[string]string
|
|
||||||
var err error
|
|
||||||
if strutil.ContainsAny(datas[0], []string{"v_r_hk", "v_hk", "v_sz", "v_sh"}) {
|
|
||||||
result, err = ParseTxHKStockData(datas)
|
|
||||||
}
|
|
||||||
|
|
||||||
//logger.SugaredLogger.Infof("股票数据解析完成: %v", result)
|
|
||||||
marshal, err := json.Marshal(result)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("json.Marshal error:%s", err.Error())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
//logger.SugaredLogger.Infof("股票数据解析完成marshal: %s", marshal)
|
|
||||||
stockInfo := &StockInfo{}
|
|
||||||
err = json.Unmarshal(marshal, &stockInfo)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("json.Unmarshal error:%s", err.Error())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
//logger.SugaredLogger.Infof("股票数据解析完成stockInfo: %+v", stockInfo)
|
|
||||||
|
|
||||||
return stockInfo, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseTxHKStockData(datas []string) (map[string]string, error) {
|
|
||||||
//v_r_hk09660="
|
|
||||||
//100~ 0
|
|
||||||
//地平线机器人-W~ 1
|
|
||||||
//09660~ 2
|
|
||||||
//6.270~ 3 当前价
|
|
||||||
//5.690~ 4 昨收价
|
|
||||||
//5.800~ 5 开盘价
|
|
||||||
//195083034.0~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//6.270~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//0~
|
|
||||||
//6.270~
|
|
||||||
//0~0~0~0~0~0~0~0~0~
|
|
||||||
//195083034.0~
|
|
||||||
//2025/04/29 13:45:41~ 30 当前时间
|
|
||||||
//0.580~
|
|
||||||
//10.19~
|
|
||||||
//6.450~ 最高价
|
|
||||||
//5.710~ 最低价
|
|
||||||
//6.270~
|
|
||||||
//195083034.0~
|
|
||||||
//1195673623.140~
|
|
||||||
//0~
|
|
||||||
//32.66
|
|
||||||
//~~0~0~13.01~694.4592~827.6584~HORIZONROBOT-W~0.00~10.380~3.320~1.06~-18.71~0~0~0~0~0~32.66~6.43~1.76~600~74.17~18.53~GP~19.70~11.51~-0.48~-18.15~45.14~13200293682.00~11075904412.00~32.66~0.000~6.129~57.14~HKD~1~30";
|
|
||||||
result := make(map[string]string)
|
|
||||||
|
|
||||||
stockCode := strutil.ReplaceWithMap(datas[0], map[string]string{
|
|
||||||
"v_r_": "",
|
|
||||||
"v_": "",
|
|
||||||
})
|
|
||||||
result["股票代码"] = stockCode
|
|
||||||
|
|
||||||
parts := strutil.SplitAndTrim(datas[1], "~")
|
|
||||||
//logger.SugaredLogger.Infof("股票数据解析完成 len: %v", len(parts))
|
|
||||||
if len(parts) < 35 {
|
|
||||||
return nil, fmt.Errorf("invalid data format")
|
|
||||||
}
|
|
||||||
result["股票名称"] = parts[1]
|
|
||||||
result["当前价格"] = parts[3]
|
|
||||||
result["昨日收盘价"] = parts[4]
|
|
||||||
result["今日开盘价"] = parts[5]
|
|
||||||
|
|
||||||
result["今日最高价"] = parts[33]
|
|
||||||
result["今日最低价"] = parts[34]
|
|
||||||
|
|
||||||
if strutil.HasPrefixAny(stockCode, []string{"sz", "sh"}) {
|
|
||||||
result["买一报价"] = parts[9]
|
|
||||||
result["买一申报"] = parts[10]
|
|
||||||
result["买二报价"] = parts[11]
|
|
||||||
result["买二申报"] = parts[12]
|
|
||||||
result["买三报价"] = parts[13]
|
|
||||||
result["买三申报"] = parts[14]
|
|
||||||
result["买四报价"] = parts[15]
|
|
||||||
result["买四申报"] = parts[16]
|
|
||||||
result["买五报价"] = parts[17]
|
|
||||||
result["买五申报"] = parts[18]
|
|
||||||
|
|
||||||
result["卖一报价"] = parts[19]
|
|
||||||
result["卖一申报"] = parts[20]
|
|
||||||
result["卖二报价"] = parts[21]
|
|
||||||
result["卖二申报"] = parts[22]
|
|
||||||
result["卖三报价"] = parts[23]
|
|
||||||
result["卖三申报"] = parts[24]
|
|
||||||
result["卖四报价"] = parts[25]
|
|
||||||
result["卖四申报"] = parts[26]
|
|
||||||
result["卖五报价"] = parts[27]
|
|
||||||
result["卖五申报"] = parts[28]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
timestr := ""
|
|
||||||
|
|
||||||
if strutil.ContainsAny(parts[30], []string{"/"}) {
|
|
||||||
timestr = strutil.ReplaceWithMap(parts[30], map[string]string{
|
|
||||||
"/": "-",
|
|
||||||
"\n": " ",
|
|
||||||
})
|
|
||||||
result["日期"] = strutil.SplitAndTrim(timestr, " ", "")[0]
|
|
||||||
result["时间"] = strutil.SplitAndTrim(timestr, " ", "")[1]
|
|
||||||
} else {
|
|
||||||
result["日期"] = strutil.Trim(parts[29])[0:4] + "-" + strutil.Trim(parts[29])[4:6] + "-" + strutil.Trim(parts[29])[6:8]
|
|
||||||
result["时间"] = strutil.Trim(parts[29])[8:10] + ":" + strutil.Trim(parts[29])[10:12] + ":" + strutil.Trim(parts[29])[12:14]
|
|
||||||
result["今日最高价"] = parts[32]
|
|
||||||
result["今日最低价"] = parts[33]
|
|
||||||
}
|
|
||||||
//logger.SugaredLogger.Infof("股票数据解析完成 %s %s 时间: %s,%s", parts[1], parts[3], parts[29], parts[30])
|
|
||||||
|
|
||||||
//logger.SugaredLogger.Infof("股票数据解析完成 时间: %v", timestr)
|
|
||||||
|
|
||||||
//logger.SugaredLogger.Infof("股票数据解析完成: %v", result)
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseFullSingleStockData(data string) (*StockInfo, error) {
|
func ParseFullSingleStockData(data string) (*StockInfo, error) {
|
||||||
datas := strutil.SplitAndTrim(data, "=", "\"")
|
datas := strutil.SplitAndTrim(data, "=", "\"")
|
||||||
if len(datas) < 2 {
|
if len(datas) < 2 {
|
||||||
@ -1342,66 +1091,6 @@ func CheckBrowserOnWindows() (string, bool) {
|
|||||||
return path + "\\msedge.exe", true
|
return path + "\\msedge.exe", true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分时数据
|
|
||||||
func (receiver StockDataApi) GetStockMinutePriceData(stockCode string) (*[]MinuteData, string) {
|
|
||||||
url := fmt.Sprintf("https://web.ifzq.gtimg.cn/appstock/app/minute/query?code=%s", stockCode)
|
|
||||||
if strutil.HasPrefixAny(stockCode, []string{"gb_", "GB_"}) {
|
|
||||||
stockCode = strings.Replace(strings.ToUpper(stockCode), "GB_", "us", 1) + ".OQ"
|
|
||||||
}
|
|
||||||
if strutil.HasPrefixAny(stockCode, []string{"us", "US"}) {
|
|
||||||
url = fmt.Sprintf("https://web.ifzq.gtimg.cn/appstock/app/UsMinute/query?code=%s", stockCode)
|
|
||||||
}
|
|
||||||
logger.SugaredLogger.Infof("GetStockMinutePriceData url:%s", url)
|
|
||||||
res := make(map[string]interface{})
|
|
||||||
resp, err := receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).R().
|
|
||||||
SetHeader("Host", "web.ifzq.gtimg.cn").
|
|
||||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
|
|
||||||
Get(url)
|
|
||||||
|
|
||||||
date := ""
|
|
||||||
minuteDatas := &[]MinuteData{}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
|
||||||
return minuteDatas, date
|
|
||||||
}
|
|
||||||
//logger.SugaredLogger.Infof("resp:%s", resp.Body())
|
|
||||||
json.Unmarshal(resp.Body(), &res)
|
|
||||||
code, _ := convertor.ToInt(res["code"])
|
|
||||||
if res["data"] != nil && code == 0 {
|
|
||||||
data := res["data"].(map[string]interface{})
|
|
||||||
if stockData, ok := data[stockCode]; ok {
|
|
||||||
m := stockData.(map[string]interface{})
|
|
||||||
if d, ok := m["data"]; ok {
|
|
||||||
if m2, ok := d.(map[string]any); ok {
|
|
||||||
minutePriceData := m2["data"]
|
|
||||||
datas := minutePriceData.([]any)
|
|
||||||
for _, item := range datas {
|
|
||||||
minuteDataSplit := strutil.SplitEx(strutil.ReplaceWithMap(item.(string), map[string]string{
|
|
||||||
"\r\n": " ",
|
|
||||||
}), " ", true)
|
|
||||||
price, _ := convertor.ToFloat(minuteDataSplit[1])
|
|
||||||
volume, _ := convertor.ToFloat(minuteDataSplit[2])
|
|
||||||
amount := float64(0)
|
|
||||||
if len(minuteDataSplit) >= 4 {
|
|
||||||
amount, _ = convertor.ToFloat(minuteDataSplit[3])
|
|
||||||
}
|
|
||||||
minuteData := &MinuteData{
|
|
||||||
Time: minuteDataSplit[0][0:2] + ":" + minuteDataSplit[0][2:4],
|
|
||||||
Price: price,
|
|
||||||
Volume: volume,
|
|
||||||
Amount: amount,
|
|
||||||
}
|
|
||||||
*minuteDatas = append(*minuteDatas, *minuteData)
|
|
||||||
}
|
|
||||||
date = m2["date"].(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return minuteDatas, date
|
|
||||||
}
|
|
||||||
|
|
||||||
func (receiver StockDataApi) GetKLineData(stockCode string, kLineType string, days int64) *[]KLineData {
|
func (receiver StockDataApi) GetKLineData(stockCode string, kLineType string, days int64) *[]KLineData {
|
||||||
url := fmt.Sprintf("http://quotes.sina.cn/cn/api/json_v2.php/CN_MarketDataService.getKLineData?symbol=%s&scale=%s&ma=yes&datalen=%d", stockCode, kLineType, days)
|
url := fmt.Sprintf("http://quotes.sina.cn/cn/api/json_v2.php/CN_MarketDataService.getKLineData?symbol=%s&scale=%s&ma=yes&datalen=%d", stockCode, kLineType, days)
|
||||||
K := &[]KLineData{}
|
K := &[]KLineData{}
|
||||||
@ -1469,192 +1158,6 @@ func (receiver StockDataApi) GetHK_KLineData(stockCode string, kLineType string,
|
|||||||
}
|
}
|
||||||
return K
|
return K
|
||||||
}
|
}
|
||||||
func (receiver StockDataApi) GetSinaHKStockInfo() {
|
|
||||||
|
|
||||||
pageSize := 500
|
|
||||||
for i := 1; i <= 3060/pageSize; i++ {
|
|
||||||
infos := getSinaStockInfo(receiver, i, pageSize)
|
|
||||||
for i, info := range *infos {
|
|
||||||
logger.SugaredLogger.Infof("infos:%d,%s:%s", i, info.Symbol, info.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSinaStockInfo(receiver StockDataApi, page, pageSize int) *[]models.SinaStockInfo {
|
|
||||||
infos := &[]models.SinaStockInfo{}
|
|
||||||
url := "https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHKStockData?page=%d&num=%d&sort=symbol&asc=1&node=qbgg_hk&_s_r_a=init"
|
|
||||||
_, err := receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).SetProxy("http://localhost:10809").R().
|
|
||||||
SetHeader("Host", "vip.stock.finance.sina.com.cn").
|
|
||||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
|
|
||||||
SetResult(infos).
|
|
||||||
Get(fmt.Sprintf(url, page, pageSize))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
|
||||||
}
|
|
||||||
return infos
|
|
||||||
}
|
|
||||||
|
|
||||||
func (receiver StockDataApi) getDCStockInfo(market string, page, pageSize int) {
|
|
||||||
//m:105,m:106,m:107 //美股
|
|
||||||
//m:128+t:3,m:128+t:4,m:128+t:1,m:128+t:2 //港股
|
|
||||||
fs := ""
|
|
||||||
switch market {
|
|
||||||
case "hk":
|
|
||||||
fs = "m:128+t:3,m:128+t:4,m:128+t:1,m:128+t:2"
|
|
||||||
case "us":
|
|
||||||
fs = "m:105,m:106,m:107"
|
|
||||||
}
|
|
||||||
|
|
||||||
url := "https://push2.eastmoney.com/api/qt/clist/get?cb=jQuery371047843066631541353_1745889398012&fs=%s&fields=f12,f13,f14,f19,f1,f2,f4,f3,f152,f17,f18,f15,f16,f5,f6&fid=f3&pn=%d&pz=%d&po=1&dect=1"
|
|
||||||
resp, err := receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).R().
|
|
||||||
SetHeader("Host", "push2.eastmoney.com").
|
|
||||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
|
|
||||||
Get(fmt.Sprintf(url, fs, page, pageSize))
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
body := string(resp.Body())
|
|
||||||
body = strutil.ReplaceWithMap(body, map[string]string{
|
|
||||||
"jQuery371047843066631541353_1745889398012(": "",
|
|
||||||
");": "",
|
|
||||||
})
|
|
||||||
js := "var d=" + body
|
|
||||||
vm := otto.New()
|
|
||||||
_, err = vm.Run(js)
|
|
||||||
_, err = vm.Run("var data = JSON.stringify(d);")
|
|
||||||
value, err := vm.Get("data")
|
|
||||||
data := make(map[string]any)
|
|
||||||
err = json.Unmarshal([]byte(value.String()), &data)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("json:%s", value.String())
|
|
||||||
logger.SugaredLogger.Errorf("json.Unmarshal error:%v", err.Error())
|
|
||||||
}
|
|
||||||
logger.SugaredLogger.Infof("resp:%s", data)
|
|
||||||
if data["data"] != nil {
|
|
||||||
datas := data["data"].(map[string]any)
|
|
||||||
total := datas["total"].(float64)
|
|
||||||
diff := datas["diff"].(map[string]any)
|
|
||||||
logger.SugaredLogger.Infof("total:%d", int(total))
|
|
||||||
for k, item := range diff {
|
|
||||||
stock := item.(map[string]any)
|
|
||||||
logger.SugaredLogger.Infof("k:%s,%s:%s", k, stock["f14"], stock["f12"])
|
|
||||||
|
|
||||||
if market == "hk" {
|
|
||||||
stockInfo := &models.StockInfoHK{
|
|
||||||
Code: strutil.PadStart(stock["f12"].(string), 5, "0") + ".HK",
|
|
||||||
Name: stock["f14"].(string),
|
|
||||||
}
|
|
||||||
db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stockInfo.Code).First(stockInfo)
|
|
||||||
logger.SugaredLogger.Infof("stockInfo:%+v", stockInfo)
|
|
||||||
if stockInfo.ID == 0 {
|
|
||||||
db.Dao.Model(&models.StockInfoHK{}).Create(stockInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if market == "us" {
|
|
||||||
stockInfo := &models.StockInfoUS{
|
|
||||||
Code: strutil.PadStart(stock["f12"].(string), 5, "0") + ".US",
|
|
||||||
Name: stock["f14"].(string),
|
|
||||||
}
|
|
||||||
db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stockInfo.Code).First(stockInfo)
|
|
||||||
logger.SugaredLogger.Infof("stockInfo:%+v", stockInfo)
|
|
||||||
if stockInfo.ID == 0 {
|
|
||||||
db.Dao.Model(&models.StockInfoUS{}).Create(stockInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (receiver StockDataApi) GetHKStockInfo(pageSize int) {
|
|
||||||
url := "https://stock.gtimg.cn/data/hk_rank.php?board=main_all&metric=price&pageSize=%d&reqPage=1&order=desc&var_name=list_data"
|
|
||||||
resp, err := receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).R().
|
|
||||||
SetHeader("Host", "stock.gtimg.cn").
|
|
||||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
|
|
||||||
Get(fmt.Sprintf(url, pageSize))
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
js := "var " + string(resp.Body())
|
|
||||||
vm := otto.New()
|
|
||||||
_, err = vm.Run(js)
|
|
||||||
_, err = vm.Run("var data = JSON.stringify(list_data);")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
value, err := vm.Get("data")
|
|
||||||
data := make(map[string]any)
|
|
||||||
err = json.Unmarshal([]byte(value.String()), &data)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("json.Unmarshal error:%v", err.Error())
|
|
||||||
}
|
|
||||||
logger.SugaredLogger.Infof("resp:%s", data)
|
|
||||||
if data["code"] != nil && data["code"].(float64) == 0 {
|
|
||||||
d := data["data"].(map[string]any)
|
|
||||||
saveHKStockInfo(d)
|
|
||||||
|
|
||||||
page_count := int64(d["page_count"].(float64))
|
|
||||||
logger.SugaredLogger.Infof("page_count:%d", page_count)
|
|
||||||
page := int64(1)
|
|
||||||
for page > page_count {
|
|
||||||
urlx := fmt.Sprintf("https://stock.gtimg.cn/data/hk_rank.php?board=main_all&metric=price&pageSize=%d&reqPage=%d&order=desc&var_name=list_data", pageSize, page)
|
|
||||||
logger.SugaredLogger.Infof("url:%s", urlx)
|
|
||||||
resp, err = receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).R().
|
|
||||||
SetHeader("Host", "stock.gtimg.cn").
|
|
||||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
|
|
||||||
Get(urlx)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
|
||||||
break
|
|
||||||
}
|
|
||||||
js = "var " + string(resp.Body())
|
|
||||||
_, err = vm.Run(js)
|
|
||||||
_, err = vm.Run("var data = JSON.stringify(list_data);")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
value, err = vm.Get("data")
|
|
||||||
data = make(map[string]any)
|
|
||||||
err = json.Unmarshal([]byte(value.String()), &data)
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Errorf("json.Unmarshal error:%v", err.Error())
|
|
||||||
}
|
|
||||||
logger.SugaredLogger.Infof("resp:%s", data)
|
|
||||||
if data != nil && data["code"] != nil && data["code"].(float64) == 0 {
|
|
||||||
if data["data"] != nil {
|
|
||||||
d = data["data"].(map[string]any)
|
|
||||||
saveHKStockInfo(d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
page++
|
|
||||||
}
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func saveHKStockInfo(d map[string]any) {
|
|
||||||
for _, v := range d["page_data"].([]any) {
|
|
||||||
vv := v.(string)
|
|
||||||
splits := strings.Split(vv, "~")
|
|
||||||
stock := &models.StockInfoHK{
|
|
||||||
Code: strutil.PadStart(splits[0], 5, "0") + ".HK",
|
|
||||||
Name: splits[1],
|
|
||||||
}
|
|
||||||
logger.SugaredLogger.Infof("vv:%s", vv)
|
|
||||||
db.Dao.Model(stock).Where("code = ?", stock.Code).First(stock)
|
|
||||||
if stock.ID == 0 {
|
|
||||||
logger.SugaredLogger.Infof("stock:%+v", stock)
|
|
||||||
db.Dao.Model(&models.StockInfoHK{}).Create(stock)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (receiver StockDataApi) GetCommonKLineData(stockCode string, kLineType string, days int64) *[]KLineData {
|
func (receiver StockDataApi) GetCommonKLineData(stockCode string, kLineType string, days int64) *[]KLineData {
|
||||||
|
|
||||||
@ -1759,10 +1262,3 @@ type KLineData struct {
|
|||||||
Close string `json:"close"`
|
Close string `json:"close"`
|
||||||
Volume string `json:"volume"`
|
Volume string `json:"volume"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MinuteData struct {
|
|
||||||
Time string `json:"time"`
|
|
||||||
Price float64 `json:"price"`
|
|
||||||
Volume float64 `json:"volume"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/v2/convertor"
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
"github.com/duke-git/lancet/v2/random"
|
|
||||||
"github.com/duke-git/lancet/v2/strutil"
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"go-stock/backend/db"
|
"go-stock/backend/db"
|
||||||
@ -47,7 +46,6 @@ func TestGetFinancialReports(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTelegraphSearch(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"
|
//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)
|
messages := SearchStockInfo("谷歌", "telegram", 30)
|
||||||
for _, message := range *messages {
|
for _, message := range *messages {
|
||||||
@ -57,27 +55,21 @@ func TestGetTelegraphSearch(t *testing.T) {
|
|||||||
//https://www.cls.cn/stock?code=sh600745
|
//https://www.cls.cn/stock?code=sh600745
|
||||||
}
|
}
|
||||||
func TestSearchStockInfoByCode(t *testing.T) {
|
func TestSearchStockInfoByCode(t *testing.T) {
|
||||||
db.Init("../../data/stock.db")
|
|
||||||
SearchStockInfoByCode("sh600745")
|
SearchStockInfoByCode("sh600745")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSearchStockPriceInfo(t *testing.T) {
|
func TestSearchStockPriceInfo(t *testing.T) {
|
||||||
db.Init("../../data/stock.db")
|
db.Init("../../data/stock.db")
|
||||||
//SearchStockPriceInfo("中信证券", "hk06030", 30)
|
//SearchStockPriceInfo("中信证券", "hk06030", 30)
|
||||||
SearchStockPriceInfo("上海贝岭", "sh600171", 30)
|
//SearchStockPriceInfo("上海贝岭", "sh600171", 30)
|
||||||
//SearchStockPriceInfo("苹果公司", "gb_aapl", 30)
|
SearchStockPriceInfo("苹果公司", "gb_aapl", 30)
|
||||||
//SearchStockPriceInfo("微创光电", "bj430198", 30)
|
//SearchStockPriceInfo("微创光电", "bj430198", 30)
|
||||||
//getZSInfo("创业板指数", "sz399006", 30)
|
getZSInfo("创业板指数", "sz399006", 30)
|
||||||
//getZSInfo("上证综合指数", "sh000001", 30)
|
//getZSInfo("上证综合指数", "sh000001", 30)
|
||||||
//getZSInfo("沪深300指数", "sh000300", 30)
|
//getZSInfo("沪深300指数", "sh000300", 30)
|
||||||
|
|
||||||
}
|
}
|
||||||
func TestGetStockMinutePriceData(t *testing.T) {
|
|
||||||
db.Init("../../data/stock.db")
|
|
||||||
data, date := NewStockDataApi().GetStockMinutePriceData("usTSLA.OQ")
|
|
||||||
logger.SugaredLogger.Infof("date:%s", date)
|
|
||||||
logger.SugaredLogger.Infof("%+#v", *data)
|
|
||||||
}
|
|
||||||
func TestGetKLineData(t *testing.T) {
|
func TestGetKLineData(t *testing.T) {
|
||||||
db.Init("../../data/stock.db")
|
db.Init("../../data/stock.db")
|
||||||
k := NewStockDataApi().GetKLineData("sh600171", "240", 30)
|
k := NewStockDataApi().GetKLineData("sh600171", "240", 30)
|
||||||
@ -104,27 +96,6 @@ func TestGetHK_KLineData(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetHKStockInfo(t *testing.T) {
|
|
||||||
db.Init("../../data/stock.db")
|
|
||||||
//NewStockDataApi().GetHKStockInfo(200)
|
|
||||||
//NewStockDataApi().GetSinaHKStockInfo()
|
|
||||||
//m:105,m:106,m:107 //美股
|
|
||||||
//m:128+t:3,m:128+t:4,m:128+t:1,m:128+t:2 //港股
|
|
||||||
for i := 1; i <= 592; i++ {
|
|
||||||
NewStockDataApi().getDCStockInfo("us", i, 20)
|
|
||||||
time.Sleep(time.Duration(random.RandInt(1, 3)) * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseTxStockData(t *testing.T) {
|
|
||||||
str := "v_r_hk09660=\"100~地平线机器人-W~09660~6.340~5.690~5.800~210980204.0~0~0~6.340~0~0~0~0~0~0~0~0~0~6.340~0~0~0~0~0~0~0~0~0~210980204.0~2025/04/29\n14:14:52~0.650~11.42~6.450~5.710~6.340~210980204.0~1295585259.040~0~33.03~~0~0~13.01~702.2123~836.8986~HORIZONROBOT-W~0.00~10.380~3.320~1.00~-53.74~0~0~0~0~0~33.03~6.50~1.90~600~76.11~19.85~GP~19.70~11.51~0.63~-17.23~46.76~13200293682.00~11075904412.00~33.03~0.000~6.141~58.90~HKD~1~30\";"
|
|
||||||
//str = "v_sz002241=\"51~歌尔股份~002241~22.26~22.27~0.00~0~0~0~22.26~1004~0.00~0~0.00~0~0.00~0~0.00~0~22.26~1004~0.00~558~0.00~0~0.00~0~0.00~0~~20250509092233~-0.01~-0.04~0.00~0.00~22.26/0/0~0~0~0.00~28.21~~0.00~0.00~0.00~686.46~777.09~2.31~24.50~20.04~0.00~-558~0.00~41.44~29.16~~~1.24~0.0000~0.0000~0~\n~GP-A~-13.75~6.76~1.09~8.18~3.39~30.63~15.70~6.87~17.47~-23.95~3083811231~3490989083~-21.75~12.02~3083811231~~~39.36~-0.04~~CNY~0~~0.00~0\";"
|
|
||||||
str = "v_sz002241=\"51~歌尔股份~002241~21.92~22.27~22.14~109872~40211~69642~21.91~25~21.90~961~21.89~257~21.88~748~21.87~665~21.92~86~21.93~168~21.94~556~21.95~171~21.96~85~~20250509094209~-0.35~-1.57~22.16~21.84~21.92/109872/241183171~109872~24118~0.36~27.78~~22.16~21.84~1.44~675.97~765.22~2.27~24.50~20.04~2.57~1590~21.95~40.80~28.71~~~1.24~24118.3171~0.0000~0~\n~GP-A~-15.07~5.13~1.11~8.18~3.39~30.63~15.70~5.23~15.67~-25.11~3083811231~3490989083~42.72~10.31~3083811231~~~37.23~0.18~~CNY~0~~21.85~1952\";"
|
|
||||||
//str = "v_r_hk09660=\"100~地平线机器人-W~09660~6.860~7.000~7.010~21157200.0~0~0~6.860~0~0~0~0~0~0~0~0~0~6.860~0~0~0~0~0~0~0~0~0~21157200.0~2025/05/09\n09:43:13~-0.140~-2.00~7.030~6.730~6.860~21157200.0~144331073.000~0~35.74~~0~0~4.29~759.8070~905.5401~HORIZONROBOT-W~0.00~10.380~3.320~2.93~11.10~0~0~0~0~0~35.74~7.04~0.19~600~90.56~4.73~GP~19.70~11.51~17.26~48.48~13.58~13200293682.00~11075904412.00~35.74~0.000~6.822~71.93~HKD~1~30\";"
|
|
||||||
info, _ := ParseTxStockData(str)
|
|
||||||
logger.SugaredLogger.Infof("%+#v", info)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetRealTimeStockPriceInfo(t *testing.T) {
|
func TestGetRealTimeStockPriceInfo(t *testing.T) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -183,7 +154,7 @@ func TestParseFullSingleStockData(t *testing.T) {
|
|||||||
func TestNewStockDataApi(t *testing.T) {
|
func TestNewStockDataApi(t *testing.T) {
|
||||||
db.Init("../../data/stock.db")
|
db.Init("../../data/stock.db")
|
||||||
stockDataApi := NewStockDataApi()
|
stockDataApi := NewStockDataApi()
|
||||||
datas, _ := stockDataApi.GetStockCodeRealTimeData("sh600859", "sh600745", "gb_tsla", "hk09660", "hk00700")
|
datas, _ := stockDataApi.GetStockCodeRealTimeData("sh600859", "sh600745", "gb_tsla")
|
||||||
for _, data := range *datas {
|
for _, data := range *datas {
|
||||||
t.Log(data)
|
t.Log(data)
|
||||||
}
|
}
|
||||||
|
@ -1,290 +0,0 @@
|
|||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"github.com/go-ego/gse"
|
|
||||||
"go-stock/backend/logger"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 金融情感词典,包含股票市场相关的专业词汇
|
|
||||||
var (
|
|
||||||
seg gse.Segmenter
|
|
||||||
|
|
||||||
// 正面金融词汇及其权重
|
|
||||||
positiveFinanceWords = map[string]float64{
|
|
||||||
"上涨": 2.0, "涨停": 3.0, "牛市": 3.0, "反弹": 2.0, "新高": 2.5,
|
|
||||||
"利好": 2.5, "增持": 2.0, "买入": 2.0, "推荐": 1.5, "看多": 2.0,
|
|
||||||
"盈利": 2.0, "增长": 2.0, "超预期": 2.5, "强劲": 1.5, "回升": 1.5,
|
|
||||||
"复苏": 2.0, "突破": 2.0, "创新高": 3.0, "回暖": 1.5, "上扬": 1.5,
|
|
||||||
"利好消息": 3.0, "收益增长": 2.5, "利润增长": 2.5, "业绩优异": 2.5,
|
|
||||||
"潜力股": 2.0, "绩优股": 2.0, "强势": 1.5, "走高": 1.5, "攀升": 1.5,
|
|
||||||
"大涨": 2.5, "飙升": 3.0, "井喷": 3.0, "爆发": 2.5, "暴涨": 3.0,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 负面金融词汇及其权重
|
|
||||||
negativeFinanceWords = map[string]float64{
|
|
||||||
"下跌": 2.0, "跌停": 3.0, "熊市": 3.0, "回调": 1.5, "新低": 2.5,
|
|
||||||
"利空": 2.5, "减持": 2.0, "卖出": 2.0, "看空": 2.0, "亏损": 2.5,
|
|
||||||
"下滑": 2.0, "萎缩": 2.0, "不及预期": 2.5, "疲软": 1.5, "恶化": 2.0,
|
|
||||||
"衰退": 2.0, "跌破": 2.0, "创新低": 3.0, "走弱": 1.5, "下挫": 1.5,
|
|
||||||
"利空消息": 3.0, "收益下降": 2.5, "利润下滑": 2.5, "业绩不佳": 2.5,
|
|
||||||
"垃圾股": 2.0, "风险股": 2.0, "弱势": 1.5, "走低": 1.5, "缩量": 2.5,
|
|
||||||
"大跌": 2.5, "暴跌": 3.0, "崩盘": 3.0, "跳水": 3.0, "重挫": 3.0,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 否定词,用于反转情感极性
|
|
||||||
negationWords = map[string]struct{}{
|
|
||||||
"不": {}, "没": {}, "无": {}, "非": {}, "未": {}, "别": {}, "勿": {},
|
|
||||||
}
|
|
||||||
|
|
||||||
// 程度副词,用于调整情感强度
|
|
||||||
degreeWords = map[string]float64{
|
|
||||||
"非常": 1.8, "极其": 2.2, "太": 1.8, "很": 1.5,
|
|
||||||
"比较": 0.8, "稍微": 0.6, "有点": 0.7, "显著": 1.5,
|
|
||||||
"大幅": 1.8, "急剧": 2.0, "轻微": 0.6, "小幅": 0.7,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转折词,用于识别情感转折
|
|
||||||
transitionWords = map[string]struct{}{
|
|
||||||
"但是": {}, "然而": {}, "不过": {}, "却": {}, "可是": {},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// 加载默认词典
|
|
||||||
err := seg.LoadDict()
|
|
||||||
if err != nil {
|
|
||||||
logger.SugaredLogger.Error(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SentimentResult 情感分析结果类型
|
|
||||||
type SentimentResult struct {
|
|
||||||
Score float64 // 情感得分
|
|
||||||
Category SentimentType // 情感类别
|
|
||||||
PositiveCount int // 正面词数量
|
|
||||||
NegativeCount int // 负面词数量
|
|
||||||
Description string // 情感描述
|
|
||||||
}
|
|
||||||
|
|
||||||
// SentimentType 情感类型枚举
|
|
||||||
type SentimentType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
Positive SentimentType = iota
|
|
||||||
Negative
|
|
||||||
Neutral
|
|
||||||
)
|
|
||||||
|
|
||||||
// AnalyzeSentiment 判断文本的情感
|
|
||||||
func AnalyzeSentiment(text string) SentimentResult {
|
|
||||||
// 初始化得分
|
|
||||||
score := 0.0
|
|
||||||
positiveCount := 0
|
|
||||||
negativeCount := 0
|
|
||||||
|
|
||||||
// 分词(简单按单个字符分割)
|
|
||||||
words := splitWords(text)
|
|
||||||
|
|
||||||
// 检查文本是否包含转折词,并分割成两部分
|
|
||||||
var transitionIndex int
|
|
||||||
var hasTransition bool
|
|
||||||
for i, word := range words {
|
|
||||||
if _, ok := transitionWords[word]; ok {
|
|
||||||
transitionIndex = i
|
|
||||||
hasTransition = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理有转折的文本
|
|
||||||
if hasTransition {
|
|
||||||
// 转折前的部分
|
|
||||||
preTransitionWords := words[:transitionIndex]
|
|
||||||
preScore, prePos, preNeg := calculateScore(preTransitionWords)
|
|
||||||
|
|
||||||
// 转折后的部分,权重加倍
|
|
||||||
postTransitionWords := words[transitionIndex+1:]
|
|
||||||
postScore, postPos, postNeg := calculateScore(postTransitionWords)
|
|
||||||
postScore *= 1.5 // 转折后的情感更重要
|
|
||||||
|
|
||||||
score = preScore + postScore
|
|
||||||
positiveCount = prePos + postPos
|
|
||||||
negativeCount = preNeg + postNeg
|
|
||||||
} else {
|
|
||||||
// 没有转折的文本
|
|
||||||
score, positiveCount, negativeCount = calculateScore(words)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确定情感类别
|
|
||||||
var category SentimentType
|
|
||||||
switch {
|
|
||||||
case score > 1.0:
|
|
||||||
category = Positive
|
|
||||||
case score < -1.0:
|
|
||||||
category = Negative
|
|
||||||
default:
|
|
||||||
category = Neutral
|
|
||||||
}
|
|
||||||
|
|
||||||
return SentimentResult{
|
|
||||||
Score: score,
|
|
||||||
Category: category,
|
|
||||||
PositiveCount: positiveCount,
|
|
||||||
NegativeCount: negativeCount,
|
|
||||||
Description: GetSentimentDescription(category),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算情感得分
|
|
||||||
func calculateScore(words []string) (float64, int, int) {
|
|
||||||
score := 0.0
|
|
||||||
positiveCount := 0
|
|
||||||
negativeCount := 0
|
|
||||||
|
|
||||||
// 遍历每个词,计算情感得分
|
|
||||||
for i, word := range words {
|
|
||||||
// 首先检查是否为程度副词
|
|
||||||
degree, isDegree := degreeWords[word]
|
|
||||||
|
|
||||||
// 检查是否为否定词
|
|
||||||
_, isNegation := negationWords[word]
|
|
||||||
|
|
||||||
// 检查是否为金融正面词
|
|
||||||
if posScore, isPositive := positiveFinanceWords[word]; isPositive {
|
|
||||||
// 检查前一个词是否为否定词或程度副词
|
|
||||||
if i > 0 {
|
|
||||||
prevWord := words[i-1]
|
|
||||||
if _, isNeg := negationWords[prevWord]; isNeg {
|
|
||||||
score -= posScore
|
|
||||||
negativeCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if deg, isDeg := degreeWords[prevWord]; isDeg {
|
|
||||||
score += posScore * deg
|
|
||||||
positiveCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
score += posScore
|
|
||||||
positiveCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否为金融负面词
|
|
||||||
if negScore, isNegative := negativeFinanceWords[word]; isNegative {
|
|
||||||
// 检查前一个词是否为否定词或程度副词
|
|
||||||
if i > 0 {
|
|
||||||
prevWord := words[i-1]
|
|
||||||
if _, isNeg := negationWords[prevWord]; isNeg {
|
|
||||||
score += negScore
|
|
||||||
positiveCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if deg, isDeg := degreeWords[prevWord]; isDeg {
|
|
||||||
score -= negScore * deg
|
|
||||||
negativeCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
score -= negScore
|
|
||||||
negativeCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理程度副词(如果后面跟着情感词)
|
|
||||||
if isDegree && i+1 < len(words) {
|
|
||||||
nextWord := words[i+1]
|
|
||||||
|
|
||||||
if posScore, isPositive := positiveFinanceWords[nextWord]; isPositive {
|
|
||||||
score += posScore * degree
|
|
||||||
positiveCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if negScore, isNegative := negativeFinanceWords[nextWord]; isNegative {
|
|
||||||
score -= negScore * degree
|
|
||||||
negativeCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理否定词(如果后面跟着情感词)
|
|
||||||
if isNegation && i+1 < len(words) {
|
|
||||||
nextWord := words[i+1]
|
|
||||||
|
|
||||||
if posScore, isPositive := positiveFinanceWords[nextWord]; isPositive {
|
|
||||||
score -= posScore
|
|
||||||
negativeCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if negScore, isNegative := negativeFinanceWords[nextWord]; isNegative {
|
|
||||||
score += negScore
|
|
||||||
positiveCount++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return score, positiveCount, negativeCount
|
|
||||||
}
|
|
||||||
|
|
||||||
// 简单的分词函数,考虑了中文和英文
|
|
||||||
func splitWords(text string) []string {
|
|
||||||
return seg.Cut(text, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSentimentDescription 获取情感类别的文本描述
|
|
||||||
func GetSentimentDescription(category SentimentType) string {
|
|
||||||
switch category {
|
|
||||||
case Positive:
|
|
||||||
return "看涨"
|
|
||||||
case Negative:
|
|
||||||
return "看跌"
|
|
||||||
case Neutral:
|
|
||||||
return "中性"
|
|
||||||
default:
|
|
||||||
return "未知"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// 从命令行读取输入
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
fmt.Println("请输入要分析的股市相关文本(输入exit退出):")
|
|
||||||
|
|
||||||
for {
|
|
||||||
fmt.Print("> ")
|
|
||||||
text, err := reader.ReadString('\n')
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("读取输入时出错:", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 去除换行符
|
|
||||||
text = strings.TrimSpace(text)
|
|
||||||
|
|
||||||
// 检查是否退出
|
|
||||||
if text == "exit" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分析情感
|
|
||||||
result := AnalyzeSentiment(text)
|
|
||||||
|
|
||||||
// 输出结果
|
|
||||||
fmt.Printf("情感分析结果: %s (得分: %.2f, 正面词:%d, 负面词:%d)\n",
|
|
||||||
GetSentimentDescription(result.Category),
|
|
||||||
result.Score,
|
|
||||||
result.PositiveCount,
|
|
||||||
result.NegativeCount)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// @Author spark
|
|
||||||
// @Date 2025/6/19 13:05
|
|
||||||
// @Desc
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func TestAnalyzeSentiment(t *testing.T) {
|
|
||||||
// 分析情感
|
|
||||||
text := " 【调查:韩国近两成中小学生过度使用智能手机或互联网】财联社6月19日电,韩国女性家族部18日公布的一项年度调查结果显示,接受调查的韩国中小学生中,共计约17.3%、即超过21万人使用智能手机或互联网的程度达到了“危险水平”,这意味着他们因过度依赖智能手机或互联网而需要关注或干预,这一比例引人担忧。 (新华社)\n"
|
|
||||||
text = "消息人士称,联合利华(Unilever)正在为Graze零食品牌寻找买家。\n"
|
|
||||||
text = "【韩国未来5年将投入51万亿韩元发展文化产业】 据韩联社,韩国文化体育观光部(文体部)今后5年将投入51万亿韩元(约合人民币2667亿元)预算,落实总统李在明在竞选时期提出的“将韩国打造成全球五大文化强国之一”的承诺。\n"
|
|
||||||
//text = "【油气股持续拉升 国际实业午后涨停】财联社6月19日电,油气股午后持续拉升,国际实业、宝莫股份午后涨停,准油股份、山东墨龙。茂化实华此前涨停,通源石油、海默科技、贝肯能源、中曼石油、科力股份等多股涨超5%。\n"
|
|
||||||
//text = " 【三大指数均跌逾1% 下跌个股近4800只】财联社6月19日电,指数持续走弱,沪指下挫跌逾1.00%,深成指跌1.25%,创业板指跌1.39%。核聚变、风电、军工、食品消费等板块指数跌幅居前,沪深京三市下跌个股近4800只。\n"
|
|
||||||
text = "【银行理财首单网下打新落地】财联社6月20日电,记者从多渠道获悉,光大理财以申报价格17元参与信通电子网下打新,并成功入围有效报价,成为行业内首家参与网下打新的银行理财公司。光大理财工作人员向证券时报记者表示,本次光大理财是以其管理的混合类产品“阳光橙增盈绝对收益策略”参与了此次网下打新,该产品为光大理财“固收+”银行理财产品。资料显示,信通电子成立于1996年,核心产品包括输电线路智能巡检系统、变电站智能辅控系统、移动智能终端及其他产品。根据其招股说明书,信通电子2023、2024年营业收入分别较上年增长19.08%和7.97%,净利润分别较上年增长5.6%和15.11%。 (证券时报)"
|
|
||||||
text = " 【以军称拦截数枚伊朗导弹】财联社6月20日电,据央视新闻报道,以军在贝尔谢巴及周边区域拦截了数枚伊朗导弹,但仍有导弹或拦截残骸落地。以色列国防军发文表示,搜救队伍正在一处“空中物体落地”的所在区域开展工作,公众目前可以离开避难场所。伊朗方面对上述说法暂无回应。"
|
|
||||||
|
|
||||||
words := splitWords(text)
|
|
||||||
fmt.Println(strings.Join(words, " "))
|
|
||||||
|
|
||||||
result := AnalyzeSentiment(text)
|
|
||||||
|
|
||||||
// 输出结果
|
|
||||||
fmt.Printf("情感分析结果: %s (得分: %.2f, 正面词:%d, 负面词:%d)\n",
|
|
||||||
result.Description,
|
|
||||||
result.Score,
|
|
||||||
result.PositiveCount,
|
|
||||||
result.NegativeCount)
|
|
||||||
|
|
||||||
}
|
|
@ -226,7 +226,6 @@ type Telegraph struct {
|
|||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
TelegraphTags []TelegraphTags `json:"tags" gorm:"-:migration;foreignKey:TelegraphId"`
|
TelegraphTags []TelegraphTags `json:"tags" gorm:"-:migration;foreignKey:TelegraphId"`
|
||||||
SentimentResult string `json:"sentimentResult" gorm:"-:all"`
|
|
||||||
}
|
}
|
||||||
type TelegraphTags struct {
|
type TelegraphTags struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
@ -251,114 +250,3 @@ func (p Tags) TableName() string {
|
|||||||
func (p Telegraph) TableName() string {
|
func (p Telegraph) TableName() string {
|
||||||
return "telegraph_list"
|
return "telegraph_list"
|
||||||
}
|
}
|
||||||
|
|
||||||
type SinaStockInfo struct {
|
|
||||||
Symbol string `json:"symbol"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Engname string `json:"engname"`
|
|
||||||
Tradetype string `json:"tradetype"`
|
|
||||||
Lasttrade string `json:"lasttrade"`
|
|
||||||
Prevclose string `json:"prevclose"`
|
|
||||||
Open string `json:"open"`
|
|
||||||
High string `json:"high"`
|
|
||||||
Low string `json:"low"`
|
|
||||||
Volume string `json:"volume"`
|
|
||||||
Currentvolume string `json:"currentvolume"`
|
|
||||||
Amount string `json:"amount"`
|
|
||||||
Ticktime string `json:"ticktime"`
|
|
||||||
Buy string `json:"buy"`
|
|
||||||
Sell string `json:"sell"`
|
|
||||||
High52Week string `json:"high_52week"`
|
|
||||||
Low52Week string `json:"low_52week"`
|
|
||||||
Eps string `json:"eps"`
|
|
||||||
Dividend string `json:"dividend"`
|
|
||||||
StocksSum string `json:"stocks_sum"`
|
|
||||||
Pricechange string `json:"pricechange"`
|
|
||||||
Changepercent string `json:"changepercent"`
|
|
||||||
MarketValue string `json:"market_value"`
|
|
||||||
PeRatio string `json:"pe_ratio"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LongTigerRankData struct {
|
|
||||||
ACCUMAMOUNT float64 `json:"ACCUM_AMOUNT"`
|
|
||||||
BILLBOARDBUYAMT float64 `json:"BILLBOARD_BUY_AMT"`
|
|
||||||
BILLBOARDDEALAMT float64 `json:"BILLBOARD_DEAL_AMT"`
|
|
||||||
BILLBOARDNETAMT float64 `json:"BILLBOARD_NET_AMT"`
|
|
||||||
BILLBOARDSELLAMT float64 `json:"BILLBOARD_SELL_AMT"`
|
|
||||||
CHANGERATE float64 `json:"CHANGE_RATE"`
|
|
||||||
CLOSEPRICE float64 `json:"CLOSE_PRICE"`
|
|
||||||
DEALAMOUNTRATIO float64 `json:"DEAL_AMOUNT_RATIO"`
|
|
||||||
DEALNETRATIO float64 `json:"DEAL_NET_RATIO"`
|
|
||||||
EXPLAIN string `json:"EXPLAIN"`
|
|
||||||
EXPLANATION string `json:"EXPLANATION"`
|
|
||||||
FREEMARKETCAP float64 `json:"FREE_MARKET_CAP"`
|
|
||||||
SECUCODE string `json:"SECUCODE" gorm:"index"`
|
|
||||||
SECURITYCODE string `json:"SECURITY_CODE"`
|
|
||||||
SECURITYNAMEABBR string `json:"SECURITY_NAME_ABBR"`
|
|
||||||
SECURITYTYPECODE string `json:"SECURITY_TYPE_CODE"`
|
|
||||||
TRADEDATE string `json:"TRADE_DATE" gorm:"index"`
|
|
||||||
TURNOVERRATE float64 `json:"TURNOVERRATE"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l LongTigerRankData) TableName() string {
|
|
||||||
return "long_tiger_rank"
|
|
||||||
}
|
|
||||||
|
|
||||||
type TVNews struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Published int `json:"published"`
|
|
||||||
Urgency int `json:"urgency"`
|
|
||||||
Permission string `json:"permission"`
|
|
||||||
StoryPath string `json:"storyPath"`
|
|
||||||
Provider struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
673
frontend/package-lock.json
generated
673
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,7 @@
|
|||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@vavt/cm-extension": "^1.8.0",
|
"@vavt/cm-extension": "^1.8.0",
|
||||||
"@vavt/v3-extension": "^3.0.0",
|
"@vavt/v3-extension": "^3.0.0",
|
||||||
"date-fns": "^4.1.0",
|
"@vicons/ionicons5": "^0.13.0",
|
||||||
"echarts": "^5.6.0",
|
"echarts": "^5.6.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"html2canvas": "^1.4.1",
|
"html2canvas": "^1.4.1",
|
||||||
@ -23,19 +23,11 @@
|
|||||||
"vue3-danmaku": "^1.6.1"
|
"vue3-danmaku": "^1.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"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",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"html-docx-js-typescript": "^0.1.5",
|
"html-docx-js-typescript": "^0.1.5",
|
||||||
"naive-ui": "^2.41.0",
|
"naive-ui": "^2.41.0",
|
||||||
"vfonts": "^0.0.3",
|
"vfonts": "^0.0.3",
|
||||||
"vite": "^6.3.5"
|
"vite": "^5.4.12"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"AI赋能股票分析",
|
"AI赋能股票分析",
|
||||||
|
@ -1 +1 @@
|
|||||||
2d63c3a999d797889c01d6c96451b197
|
99aeae4d0e7cbe900b379d3e7d2f44d7
|
@ -1,56 +1,33 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
EventsEmit,
|
EventsEmit,
|
||||||
EventsOff,
|
|
||||||
EventsOn,
|
EventsOn,
|
||||||
Quit,
|
Quit,
|
||||||
WindowFullscreen,
|
WindowFullscreen, WindowGetPosition,
|
||||||
WindowHide,
|
WindowHide,
|
||||||
|
WindowSetPosition,
|
||||||
WindowUnfullscreen
|
WindowUnfullscreen
|
||||||
} from '../wailsjs/runtime'
|
} from '../wailsjs/runtime'
|
||||||
import {h, onBeforeMount, onBeforeUnmount, onMounted, ref} from "vue";
|
import {h, onBeforeMount, onMounted, ref} from "vue";
|
||||||
import {RouterLink, useRouter} from 'vue-router'
|
import { RouterLink } from 'vue-router'
|
||||||
import {createDiscreteApi,darkTheme,lightTheme , NIcon, NText,dateZhCN,zhCN} from 'naive-ui'
|
import {darkTheme, NGradientText, NIcon, NText,} from 'naive-ui'
|
||||||
import {
|
import {
|
||||||
AlarmOutline,
|
SettingsOutline,
|
||||||
AnalyticsOutline,
|
|
||||||
BarChartSharp, Bonfire, BonfireOutline, EaselSharp,
|
|
||||||
ExpandOutline, Flag,
|
|
||||||
Flame, FlameSharp, InformationOutline,
|
|
||||||
LogoGithub,
|
|
||||||
NewspaperOutline,
|
|
||||||
NewspaperSharp, Notifications,
|
|
||||||
PowerOutline, Pulse,
|
|
||||||
ReorderTwoOutline,
|
ReorderTwoOutline,
|
||||||
SettingsOutline, Skull, SkullOutline, SkullSharp,
|
ExpandOutline,
|
||||||
SparklesOutline,
|
PowerOutline, LogoGithub, MoveOutline, WalletOutline, StarOutline, AlarmOutline, SparklesOutline, NewspaperOutline,
|
||||||
StarOutline,
|
|
||||||
Wallet, WarningOutline,
|
|
||||||
} from '@vicons/ionicons5'
|
} from '@vicons/ionicons5'
|
||||||
import {AnalyzeSentiment, GetConfig, GetGroupList} from "../wailsjs/go/main/App";
|
import {GetConfig} 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";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const loading = ref(true)
|
|
||||||
const loadingMsg = ref("加载数据中...")
|
|
||||||
const enableNews= ref(false)
|
const enableNews= ref(false)
|
||||||
const contentStyle = ref("")
|
const contentStyle = ref("")
|
||||||
const enableFund = ref(false)
|
const enableFund = ref(false)
|
||||||
const enableDarkTheme = ref(null)
|
const enableDarkTheme = ref(null)
|
||||||
const content = ref('数据来源于网络,仅供参考;投资有风险,入市需谨慎\n\n未经授权,禁止商业目的!')
|
const content = ref('数据来源于网络,仅供参考;投资有风险,入市需谨慎')
|
||||||
const isFullscreen = ref(false)
|
const isFullscreen = ref(false)
|
||||||
const activeKey = ref('')
|
const activeKey = ref('')
|
||||||
const containerRef= ref({})
|
const containerRef= ref({})
|
||||||
const realtimeProfit= ref(0)
|
const realtimeProfit= ref(0)
|
||||||
const telegraph= ref([])
|
const telegraph= ref([])
|
||||||
const groupList = ref([])
|
|
||||||
const menuOptions = ref([
|
const menuOptions = ref([
|
||||||
{
|
{
|
||||||
label: () =>
|
label: () =>
|
||||||
@ -59,11 +36,8 @@ const menuOptions = ref([
|
|||||||
{
|
{
|
||||||
to: {
|
to: {
|
||||||
name: 'stock',
|
name: 'stock',
|
||||||
query: {
|
params: {
|
||||||
groupName: '全部',
|
|
||||||
groupId: 0,
|
|
||||||
},
|
},
|
||||||
params: {},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ default: () => '股票自选',}
|
{ default: () => '股票自选',}
|
||||||
@ -72,289 +46,29 @@ const menuOptions = ref([
|
|||||||
icon: renderIcon(StarOutline),
|
icon: renderIcon(StarOutline),
|
||||||
children:[
|
children:[
|
||||||
{
|
{
|
||||||
label: () =>
|
label: ()=> h(NText, {type:realtimeProfit.value>0?'error':'success'},{ default: () => '当日盈亏 '+realtimeProfit.value+"¥"}),
|
||||||
h(
|
key: 'realtimeProfit',
|
||||||
'a',
|
show: realtimeProfit.value,
|
||||||
{
|
icon: renderIcon(WalletOutline),
|
||||||
href: '#',
|
|
||||||
type: 'info',
|
|
||||||
onClick: () => {
|
|
||||||
//console.log("push",item)
|
|
||||||
router.push({
|
|
||||||
name: 'stock',
|
|
||||||
query: {
|
|
||||||
groupName: '全部',
|
|
||||||
groupId: 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
EventsEmit("changeTab", {ID: 0, name: '全部'})
|
|
||||||
},
|
|
||||||
to: {
|
|
||||||
name: 'stock',
|
|
||||||
query: {
|
|
||||||
groupName: '全部',
|
|
||||||
groupId: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{default: () => '全部',}
|
|
||||||
),
|
|
||||||
key: 0,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
params: {}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '市场快讯'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '市场行情'}
|
|
||||||
),
|
|
||||||
key: 'market',
|
|
||||||
icon: renderIcon(NewspaperOutline),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "市场快讯",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '市场快讯'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '市场快讯',}
|
|
||||||
),
|
|
||||||
key: 'market1',
|
|
||||||
icon: renderIcon(NewspaperSharp),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "全球股指",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '全球股指'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '全球股指',}
|
|
||||||
),
|
|
||||||
key: 'market2',
|
|
||||||
icon: renderIcon(BarChartSharp),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "指标行情",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '指标行情'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '指标行情',}
|
|
||||||
),
|
|
||||||
key: 'market3',
|
|
||||||
icon: renderIcon(AnalyticsOutline),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "行业排名",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '行业排名'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '行业排名',}
|
|
||||||
),
|
|
||||||
key: 'market4',
|
|
||||||
icon: renderIcon(Flag),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "个股资金流向",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '个股资金流向'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '个股资金流向',}
|
|
||||||
),
|
|
||||||
key: 'market5',
|
|
||||||
icon: renderIcon(Pulse),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "龙虎榜",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '龙虎榜'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '龙虎榜',}
|
|
||||||
),
|
|
||||||
key: 'market6',
|
|
||||||
icon: renderIcon(Dragon),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "个股研报",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '个股研报'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '个股研报',}
|
|
||||||
),
|
|
||||||
key: 'market7',
|
|
||||||
icon: renderIcon(StockOutlined),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "公司公告",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '公司公告'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '公司公告',}
|
|
||||||
),
|
|
||||||
key: 'market8',
|
|
||||||
icon: renderIcon(NotificationFilled),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
to: {
|
|
||||||
name: 'market',
|
|
||||||
query: {
|
|
||||||
name: "行业研究",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
EventsEmit("changeMarketTab", {ID: 0, name: '行业研究'})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{default: () => '行业研究',}
|
|
||||||
),
|
|
||||||
key: 'market9',
|
|
||||||
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),
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
name: 'market',
|
||||||
|
params: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ default: () => '市场行情' }
|
||||||
|
),
|
||||||
|
key: 'market',
|
||||||
|
icon: renderIcon(NewspaperOutline),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: () =>
|
label: () =>
|
||||||
h(
|
h(
|
||||||
@ -362,7 +76,8 @@ const menuOptions = ref([
|
|||||||
{
|
{
|
||||||
to: {
|
to: {
|
||||||
name: 'fund',
|
name: 'fund',
|
||||||
params: {},
|
params: {
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ default: () => '基金自选',}
|
{ default: () => '基金自选',}
|
||||||
@ -386,7 +101,8 @@ const menuOptions = ref([
|
|||||||
{
|
{
|
||||||
to: {
|
to: {
|
||||||
name: 'settings',
|
name: 'settings',
|
||||||
params: {}
|
params: {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ default: () => '设置' }
|
{ default: () => '设置' }
|
||||||
@ -401,7 +117,8 @@ const menuOptions = ref([
|
|||||||
{
|
{
|
||||||
to: {
|
to: {
|
||||||
name: 'about',
|
name: 'about',
|
||||||
params: {}
|
params: {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ default: () => '关于' }
|
{ default: () => '关于' }
|
||||||
@ -445,11 +162,9 @@ const menuOptions = ref([
|
|||||||
icon: renderIcon(PowerOutline),
|
icon: renderIcon(PowerOutline),
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
function renderIcon(icon) {
|
function renderIcon(icon) {
|
||||||
return () => h(NIcon, null, { default: () => h(icon) })
|
return () => h(NIcon, null, { default: () => h(icon) })
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleFullscreen(e) {
|
function toggleFullscreen(e) {
|
||||||
//console.log(e)
|
//console.log(e)
|
||||||
if (isFullscreen.value) {
|
if (isFullscreen.value) {
|
||||||
@ -461,7 +176,6 @@ function toggleFullscreen(e) {
|
|||||||
}
|
}
|
||||||
isFullscreen.value=!isFullscreen.value
|
isFullscreen.value=!isFullscreen.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// const drag = ref(false)
|
// const drag = ref(false)
|
||||||
// const lastPos= ref({x:0,y:0})
|
// const lastPos= ref({x:0,y:0})
|
||||||
// function toggleStartMoveWindow(e) {
|
// function toggleStartMoveWindow(e) {
|
||||||
@ -486,24 +200,6 @@ EventsOn("telegraph", (data) => {
|
|||||||
telegraph.value=data
|
telegraph.value=data
|
||||||
})
|
})
|
||||||
|
|
||||||
EventsOn("loadingMsg", (data) => {
|
|
||||||
if(data==="done"){
|
|
||||||
loadingMsg.value = "加载完成..."
|
|
||||||
EventsEmit("loadingDone", "app")
|
|
||||||
loading.value = false
|
|
||||||
}else{
|
|
||||||
loading.value = true
|
|
||||||
loadingMsg.value = data
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
EventsOff("realtime_profit")
|
|
||||||
EventsOff("loadingMsg")
|
|
||||||
EventsOff("telegraph")
|
|
||||||
EventsOff("newsPush")
|
|
||||||
})
|
|
||||||
|
|
||||||
window.onerror = function (msg, source, lineno, colno, error) {
|
window.onerror = function (msg, source, lineno, colno, error) {
|
||||||
// 将错误信息发送给后端
|
// 将错误信息发送给后端
|
||||||
EventsEmit("frontendError", {
|
EventsEmit("frontendError", {
|
||||||
@ -518,52 +214,8 @@ window.onerror = function (msg, source, lineno, colno, error) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onBeforeMount(()=>{
|
onBeforeMount(()=>{
|
||||||
GetGroupList().then(result => {
|
|
||||||
groupList.value = result
|
|
||||||
menuOptions.value.map((item) => {
|
|
||||||
//console.log(item)
|
|
||||||
if (item.key === 'stock') {
|
|
||||||
item.children.push(...groupList.value.map(item => {
|
|
||||||
return {
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
'a',
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
type: 'info',
|
|
||||||
onClick: () => {
|
|
||||||
//console.log("push",item)
|
|
||||||
router.push({
|
|
||||||
name: 'stock',
|
|
||||||
query: {
|
|
||||||
groupName: item.name,
|
|
||||||
groupId: item.ID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
EventsEmit("changeTab", item)
|
|
||||||
}, 100)
|
|
||||||
},
|
|
||||||
to: {
|
|
||||||
name: 'stock',
|
|
||||||
query: {
|
|
||||||
groupName: item.name,
|
|
||||||
groupId: item.ID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{default: () => item.name,}
|
|
||||||
),
|
|
||||||
key: item.ID,
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
GetConfig().then((res)=>{
|
GetConfig().then((res)=>{
|
||||||
//console.log(res)
|
console.log(res)
|
||||||
enableFund.value=res.enableFund
|
enableFund.value=res.enableFund
|
||||||
|
|
||||||
menuOptions.value.filter((item)=>{
|
menuOptions.value.filter((item)=>{
|
||||||
@ -581,49 +233,23 @@ onBeforeMount(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
contentStyle.value = "max-height: calc(92vh);overflow: hidden"
|
contentStyle.value="max-height: calc(90vh);overflow: hidden"
|
||||||
GetConfig().then((res)=>{
|
GetConfig().then((res)=>{
|
||||||
if(res.enableNews){
|
if(res.enableNews){
|
||||||
enableNews.value=true
|
enableNews.value=true
|
||||||
}
|
}
|
||||||
enableFund.value=res.enableFund
|
enableFund.value=res.enableFund
|
||||||
const {notification } =createDiscreteApi(["notification"], {
|
|
||||||
configProviderProps: {
|
|
||||||
theme: enableDarkTheme.value ? darkTheme : lightTheme ,
|
|
||||||
max: 3,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
EventsOn("newsPush", (data) => {
|
|
||||||
//console.log(data)
|
|
||||||
if(data.isRed){
|
|
||||||
notification.create({
|
|
||||||
//type:"error",
|
|
||||||
// avatar: () => h(NIcon,{component:Notifications,color:"red"}),
|
|
||||||
title: data.time,
|
|
||||||
content: () => h(NText,{type:"error"}, { default: () => data.content }),
|
|
||||||
meta: () => h(NText,{type:"warning"}, { default: () => data.source}),
|
|
||||||
duration:1000*40,
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
notification.create({
|
|
||||||
//type:"info",
|
|
||||||
//avatar: () => h(NIcon,{component:Notifications}),
|
|
||||||
title: data.time,
|
|
||||||
content: () => h(NText,{type:"info"}, { default: () => data.content }),
|
|
||||||
meta: () => h(NText,{type:"warning"}, { default: () => data.source}),
|
|
||||||
duration:1000*30 ,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<n-config-provider ref="containerRef" :theme="enableDarkTheme" :locale="zhCN" :date-locale="dateZhCN">
|
<n-config-provider ref="containerRef" :theme="enableDarkTheme" >
|
||||||
<n-message-provider >
|
<n-message-provider >
|
||||||
<n-notification-provider>
|
<n-notification-provider>
|
||||||
<n-modal-provider>
|
<n-modal-provider>
|
||||||
<n-dialog-provider>
|
<n-dialog-provider>
|
||||||
|
|
||||||
<n-watermark
|
<n-watermark
|
||||||
:content="content"
|
:content="content"
|
||||||
cross
|
cross
|
||||||
@ -638,23 +264,25 @@ onMounted(() => {
|
|||||||
>
|
>
|
||||||
<n-flex>
|
<n-flex>
|
||||||
<n-grid x-gap="12" :cols="1">
|
<n-grid x-gap="12" :cols="1">
|
||||||
|
<!--
|
||||||
|
<n-gi style="position: relative;top:1px;z-index: 19;width: 100%" v-if="telegraph.length>0">
|
||||||
|
|
||||||
|
</n-gi>
|
||||||
|
-->
|
||||||
|
|
||||||
<n-gi>
|
<n-gi>
|
||||||
<n-spin :show="loading">
|
<n-marquee :speed="100" style="position: relative;top:0;z-index: 19;width: 100%" v-if="(telegraph.length>0)&&(enableNews)">
|
||||||
<template #description>
|
|
||||||
{{ loadingMsg }}
|
|
||||||
</template>
|
|
||||||
<n-marquee :speed="100" style="position: relative;top:0;z-index: 19;width: 100%"
|
|
||||||
v-if="(telegraph.length>0)&&(enableNews)">
|
|
||||||
<n-tag type="warning" v-for="item in telegraph" style="margin-right: 10px">
|
<n-tag type="warning" v-for="item in telegraph" style="margin-right: 10px">
|
||||||
{{item}}
|
{{item}}
|
||||||
</n-tag>
|
</n-tag>
|
||||||
|
<!-- <n-text type="warning"> {{telegraph[0]}}</n-text>-->
|
||||||
</n-marquee>
|
</n-marquee>
|
||||||
<n-scrollbar :style="contentStyle">
|
<n-scrollbar :style="contentStyle">
|
||||||
<n-skeleton v-if="loading" height="calc(100vh)" />
|
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
</n-spin>
|
|
||||||
</n-gi>
|
</n-gi>
|
||||||
|
|
||||||
|
|
||||||
<n-gi style="position: fixed;bottom:0;z-index: 9;width: 100%;">
|
<n-gi style="position: fixed;bottom:0;z-index: 9;width: 100%;">
|
||||||
<n-card size="small" style="--wails-draggable:drag">
|
<n-card size="small" style="--wails-draggable:drag">
|
||||||
<n-menu style="font-size: 18px;"
|
<n-menu style="font-size: 18px;"
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {nextTick, onBeforeMount, onMounted, onUnmounted, ref} from 'vue'
|
|
||||||
import {ClsCalendar} from "../../wailsjs/go/main/App";
|
|
||||||
import { addMonths, format ,parse} from 'date-fns';
|
|
||||||
import { zhCN } from 'date-fns/locale';
|
|
||||||
|
|
||||||
import {useMessage} from 'naive-ui'
|
|
||||||
import {Star48Filled} from "@vicons/fluent";
|
|
||||||
const today = new Date();
|
|
||||||
const year = today.getFullYear();
|
|
||||||
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
|
|
||||||
const day = String(today.getDate()).padStart(2, '0');
|
|
||||||
|
|
||||||
// 常见格式:YYYY-MM-DD
|
|
||||||
const formattedDate = `${year}-${month}-${day}`;
|
|
||||||
const formattedYM = `${year}-${month}`;
|
|
||||||
const list = ref([])
|
|
||||||
const message=useMessage()
|
|
||||||
|
|
||||||
function goBackToday() {
|
|
||||||
setTimeout(() => {
|
|
||||||
nextTick(
|
|
||||||
() => {
|
|
||||||
const elementById = document.getElementById(formattedDate);
|
|
||||||
if (elementById) {
|
|
||||||
elementById.scrollIntoView({
|
|
||||||
behavior: 'auto',
|
|
||||||
block: 'start'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
ClsCalendar().then(res => {
|
|
||||||
list.value = res
|
|
||||||
goBackToday();
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function getweekday(date){
|
|
||||||
let day=parse(date, 'yyyy-MM-dd', new Date())
|
|
||||||
return format(day, 'EEEE', {locale: zhCN})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- <n-timeline size="large" style="text-align: left">-->
|
|
||||||
<!-- <n-timeline-item v-for="item in list" :key="item.date" :title="item.date" type="info" >-->
|
|
||||||
<!-- <n-list>-->
|
|
||||||
<!-- <n-list-item v-for="l in item.list" :key="l.article_id ">-->
|
|
||||||
<!-- <n-text>{{l.title}}</n-text>-->
|
|
||||||
<!-- </n-list-item>-->
|
|
||||||
<!-- </n-list>-->
|
|
||||||
<!-- </n-timeline-item>-->
|
|
||||||
<!-- </n-timeline>-->
|
|
||||||
|
|
||||||
<n-list bordered style="max-height: calc(100vh - 230px);text-align: left;">
|
|
||||||
<n-scrollbar style="max-height: calc(100vh - 230px);" >
|
|
||||||
<n-list-item v-for="(item, index) in list" :id="item.calendar_day" :key="item.calendar_day">
|
|
||||||
<n-thing :title="item.calendar_day +' '+item.week">
|
|
||||||
<n-list :bordered="false" hoverable>
|
|
||||||
<n-list-item v-for="(l,i ) in item.items" :key="l.id ">
|
|
||||||
<n-flex justify="space-between">
|
|
||||||
<n-text :type="item.calendar_day===formattedDate?'warning':'info'">{{i+1}}# {{l.title}}
|
|
||||||
<n-tag v-if="l.event" size="small" round type="success">事件</n-tag>
|
|
||||||
<n-tag v-if="l.economic" size="small" round type="error">数据</n-tag>
|
|
||||||
</n-text>
|
|
||||||
<n-rate v-if="l.event&&(l.event.star>0)" readonly :default-value="l.event.star">
|
|
||||||
<n-icon :component="Star48Filled"/>
|
|
||||||
</n-rate>
|
|
||||||
<n-rate v-if="l.economic&&(l.economic.star>0)" readonly :default-value="l.economic.star" >
|
|
||||||
<n-icon :component="Star48Filled"/>
|
|
||||||
</n-rate>
|
|
||||||
</n-flex>
|
|
||||||
|
|
||||||
<n-flex v-if="l.economic">
|
|
||||||
<n-tag type="warning" :bordered="false" :size="'small'">公布:{{l.economic.actual }}</n-tag>
|
|
||||||
<n-tag type="warning" :bordered="false" :size="'small'">预测:{{l.economic.consensus}}</n-tag>
|
|
||||||
<n-tag type="warning" :bordered="false" :size="'small'">前值:{{l.economic.front}}</n-tag>
|
|
||||||
</n-flex>
|
|
||||||
</n-list-item>
|
|
||||||
</n-list>
|
|
||||||
</n-thing>
|
|
||||||
</n-list-item>
|
|
||||||
<n-list-item v-if="list.length==0">
|
|
||||||
<n-text type="info">没有数据</n-text>
|
|
||||||
</n-list-item>
|
|
||||||
<n-list-item v-else style="text-align: center;">
|
|
||||||
<n-button-group>
|
|
||||||
<n-button strong secondary type="warning" @click="goBackToday">回到今天</n-button>
|
|
||||||
</n-button-group>
|
|
||||||
</n-list-item>
|
|
||||||
</n-scrollbar>
|
|
||||||
</n-list>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,37 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {onBeforeMount, onUnmounted, ref} from 'vue'
|
|
||||||
import {HotEvent} from "../../wailsjs/go/main/App";
|
|
||||||
const list = ref([])
|
|
||||||
|
|
||||||
const task =ref()
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
list.value = await HotEvent(50)
|
|
||||||
task.value=setInterval(async ()=>{
|
|
||||||
list.value = await HotEvent(50)
|
|
||||||
}, 1000*10)
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(async ()=>{
|
|
||||||
clearInterval(task.value)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-list bordered>
|
|
||||||
<template #header>
|
|
||||||
雪球热门
|
|
||||||
</template>
|
|
||||||
<n-list-item v-for="(item, index) in list" :key="index">
|
|
||||||
<n-thing :title="item.tag" :description="item.content" >
|
|
||||||
<template v-if="item.pic" #avatar>
|
|
||||||
<n-avatar :src="item.pic" :size="60">
|
|
||||||
</n-avatar>
|
|
||||||
</template>
|
|
||||||
</n-thing>
|
|
||||||
</n-list-item>
|
|
||||||
</n-list>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,88 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {onBeforeMount, onUnmounted, ref} from 'vue'
|
|
||||||
import {HotStock} from "../../wailsjs/go/main/App";
|
|
||||||
import KLineChart from "./KLineChart.vue";
|
|
||||||
import {ArrowBack, ArrowDown, ArrowUp} from "@vicons/ionicons5";
|
|
||||||
|
|
||||||
const {marketType}=defineProps(
|
|
||||||
{
|
|
||||||
marketType: {
|
|
||||||
type: String,
|
|
||||||
default: '10'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const task =ref()
|
|
||||||
|
|
||||||
const list = ref([])
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
list.value = await HotStock(marketType)
|
|
||||||
task.value = setInterval(async () => {
|
|
||||||
list.value = await HotStock(marketType)
|
|
||||||
}, 5000)
|
|
||||||
})
|
|
||||||
onUnmounted(()=>{
|
|
||||||
clearInterval(task.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
function getMarketCode(item) {
|
|
||||||
if (item.exchange === 'SZ') {
|
|
||||||
return item.code.toLowerCase()
|
|
||||||
}
|
|
||||||
if (item.exchange === 'SH') {
|
|
||||||
return item.code.toLowerCase()
|
|
||||||
}
|
|
||||||
if (item.exchange === 'HK') {
|
|
||||||
return (item.exchange + item.code).toLowerCase()
|
|
||||||
}
|
|
||||||
return ("gb_"+item.code).toLowerCase()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-table striped size="small">
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<n-th>股票名称</n-th>
|
|
||||||
<n-th>涨跌幅</n-th>
|
|
||||||
<n-th>当前价格</n-th>
|
|
||||||
<n-th>热度</n-th>
|
|
||||||
<n-th>热度变化</n-th>
|
|
||||||
<n-th>排名变化</n-th>
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="item in list" :key="item.code">
|
|
||||||
<n-td><n-text type="info">
|
|
||||||
<n-popover trigger="hover" placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<n-tag type="info" :bordered="false"> {{item.name}} {{item.code}}</n-tag>
|
|
||||||
</template>
|
|
||||||
<k-line-chart style="width: 800px" :code="getMarketCode(item)" :chart-height="500" :name="item.name" :k-days="20" :dark-theme="true"></k-line-chart>
|
|
||||||
</n-popover>
|
|
||||||
</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.percent>0?'error':'success'">{{item.percent}}%</n-text></n-td>
|
|
||||||
<n-td><n-text type="info">{{item.current}}</n-text></n-td>
|
|
||||||
<n-td><n-text type="info">{{item.value}}</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.increment>0?'error':'success'">
|
|
||||||
{{item.increment}}
|
|
||||||
<n-icon v-if="item.increment>0" :component="ArrowUp"/>
|
|
||||||
<n-icon v-else :component="ArrowDown"/>
|
|
||||||
</n-text></n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.rank_change>0?'error':'success'">
|
|
||||||
{{item.rank_change}}
|
|
||||||
<n-icon v-if="item.rank_change>0" :component="ArrowUp"/>
|
|
||||||
<n-text v-else-if="item.rank_change==0" ></n-text>
|
|
||||||
<n-icon v-else :component="ArrowDown"/>
|
|
||||||
</n-text>
|
|
||||||
</n-td>
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,73 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {onBeforeMount, onUnmounted, ref} from 'vue'
|
|
||||||
import {HotTopic} from "../../wailsjs/go/main/App";
|
|
||||||
const list = ref([])
|
|
||||||
const task =ref()
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
list.value = await HotTopic(10)
|
|
||||||
setInterval(async ()=>{
|
|
||||||
list.value = await HotTopic(10)
|
|
||||||
}, 1000*10)
|
|
||||||
})
|
|
||||||
onUnmounted(()=>{
|
|
||||||
clearInterval(task.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
function openCenteredWindow(url, width, height) {
|
|
||||||
const left = (window.screen.width - width) / 2;
|
|
||||||
const top = (window.screen.height - height) / 2;
|
|
||||||
|
|
||||||
return window.open(
|
|
||||||
url,
|
|
||||||
'centeredWindow',
|
|
||||||
`width=${width},height=${height},left=${left},top=${top}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function showPage(htid) {
|
|
||||||
openCenteredWindow(`https://gubatopic.eastmoney.com/topic_v3.html?htid=${htid}`, 1000, 600)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-list bordered hoverable clickable>
|
|
||||||
<!-- <template #header>-->
|
|
||||||
<!-- 股吧热门-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<n-list-item v-for="(item, index) in list" :key="index">
|
|
||||||
<n-thing :title="item.nickname" :description="item.desc" :description-style="'font-size: 14px;'" @click="showPage(item.htid)">
|
|
||||||
<template v-if="item.squareImg" #avatar>
|
|
||||||
<n-avatar :src="item.squareImg" :size="60">
|
|
||||||
</n-avatar>
|
|
||||||
</template>
|
|
||||||
<template v-if="item.stock_list" #footer>
|
|
||||||
<n-flex>
|
|
||||||
<n-tag type="info" v-for="(v, i) in item.stock_list" :bordered="false" size="small">
|
|
||||||
{{v.name}}
|
|
||||||
</n-tag>
|
|
||||||
</n-flex>
|
|
||||||
</template>
|
|
||||||
<template v-if="item.clickNumber" #header-extra>
|
|
||||||
<n-flex>
|
|
||||||
<n-button secondary type="warning" size="tiny">讨论数:<n-number-animation
|
|
||||||
show-separator
|
|
||||||
:from="0"
|
|
||||||
:to="item.postNumber"
|
|
||||||
/>
|
|
||||||
</n-button >
|
|
||||||
<n-tag :bordered="false" type="warning" size="small">浏览量:<n-number-animation
|
|
||||||
show-separator
|
|
||||||
:from="0"
|
|
||||||
:to="item.clickNumber"
|
|
||||||
/>
|
|
||||||
</n-tag>
|
|
||||||
</n-flex>
|
|
||||||
</template>
|
|
||||||
</n-thing>
|
|
||||||
</n-list-item>
|
|
||||||
</n-list>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,115 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {onBeforeMount, ref} from 'vue'
|
|
||||||
import {GetStockList, IndustryResearchReport,EMDictCode} from "../../wailsjs/go/main/App";
|
|
||||||
import {ArrowDownOutline, CaretDown, CaretUp, PulseOutline, Refresh, RefreshCircleSharp,} from "@vicons/ionicons5";
|
|
||||||
|
|
||||||
import {useMessage} from "naive-ui";
|
|
||||||
import {BrowserOpenURL} from "../../wailsjs/runtime";
|
|
||||||
|
|
||||||
const message=useMessage()
|
|
||||||
const list = ref([])
|
|
||||||
|
|
||||||
const options = ref([])
|
|
||||||
|
|
||||||
function getIndustryResearchReport(value) {
|
|
||||||
message.loading("正在刷新数据...")
|
|
||||||
IndustryResearchReport(value).then(result => {
|
|
||||||
console.log(result)
|
|
||||||
list.value = result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(()=>{
|
|
||||||
getIndustryResearchReport('');
|
|
||||||
})
|
|
||||||
|
|
||||||
function ratingChangeName(ratingChange){
|
|
||||||
if(ratingChange===0){
|
|
||||||
return '调高'
|
|
||||||
}else if(ratingChange===1){
|
|
||||||
return '调低'
|
|
||||||
}else if(ratingChange===2){
|
|
||||||
return '首次'
|
|
||||||
}else if(ratingChange===3){
|
|
||||||
return '维持'
|
|
||||||
}else if (ratingChange===4){
|
|
||||||
return '无变化'
|
|
||||||
}else{
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function openWin(code) {
|
|
||||||
BrowserOpenURL("https://pdf.dfcfw.com/pdf/H3_"+code+"_1.pdf?1749744888000.pdf")
|
|
||||||
}
|
|
||||||
|
|
||||||
function EMDictCodeList(keyVal){
|
|
||||||
if (keyVal){
|
|
||||||
EMDictCode('016').then(result => {
|
|
||||||
console.log(result)
|
|
||||||
options.value=result.filter((value,index,array) => value.bkName.includes(keyVal)||value.firstLetter.includes(keyVal)||value.bkCode.includes(keyVal)).map(item => {
|
|
||||||
return {
|
|
||||||
label: item.bkName+" - "+item.bkCode,
|
|
||||||
value: item.bkCode
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
getIndustryResearchReport('')
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
function handleSearch(value) {
|
|
||||||
getIndustryResearchReport(value)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-card>
|
|
||||||
<n-auto-complete :options="options" placeholder="请输入行业名称关键词搜索" clearable filterable :on-select="handleSearch" :on-update:value="EMDictCodeList" />
|
|
||||||
</n-card>
|
|
||||||
<n-table striped size="small">
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<!-- <n-th>代码</n-th>-->
|
|
||||||
<!-- <n-th>名称</n-th>-->
|
|
||||||
<n-th>行业</n-th>
|
|
||||||
<n-th>标题</n-th>
|
|
||||||
<n-th>东财评级</n-th>
|
|
||||||
<n-th>评级变动</n-th>
|
|
||||||
<n-th>机构评级</n-th>
|
|
||||||
<n-th>分析师</n-th>
|
|
||||||
<n-th>机构</n-th>
|
|
||||||
<n-th> <n-flex justify="space-between">日期<n-icon @click="getIndustryResearchReport" color="#409EFF" :size="20" :component="RefreshCircleSharp"/></n-flex></n-th>
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="item in list" :key="item.infoCode">
|
|
||||||
<!-- <n-td>{{item.stockCode}}</n-td>-->
|
|
||||||
<!-- <n-td :title="item.stockCode">-->
|
|
||||||
<!-- <n-popover trigger="hover" placement="right">-->
|
|
||||||
<!-- <template #trigger>-->
|
|
||||||
<!-- <n-tag type="info" :bordered="false">{{item.stockName}}</n-tag>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- <k-line-chart style="width: 800px" :code="getmMarketCode(item.market,item.stockCode)" :chart-height="500" :name="item.stockName" :k-days="20" :dark-theme="true"></k-line-chart>-->
|
|
||||||
<!-- </n-popover>-->
|
|
||||||
<!-- </n-td>-->
|
|
||||||
<n-td><n-tag type="info" :bordered="false">{{item.industryName}}</n-tag></n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-a type="info" @click="openWin(item.infoCode)"><n-text type="success">{{item.title}}</n-text></n-a>
|
|
||||||
</n-td>
|
|
||||||
<n-td><n-text :type="item.emRatingName==='增持'?'error':'info'">
|
|
||||||
{{item.emRatingName}}
|
|
||||||
</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.ratingChange===0?'error':'info'">{{ratingChangeName(item.ratingChange)}}</n-text></n-td>
|
|
||||||
<n-td>{{item.sRatingName }}</n-td>
|
|
||||||
<n-td><n-ellipsis style="max-width: 120px">{{item.researcher}}</n-ellipsis></n-td>
|
|
||||||
<n-td>{{item.orgSName}}</n-td>
|
|
||||||
<n-td>{{item.publishDate.substring(0,10)}}</n-td>
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,108 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {nextTick, onBeforeMount, onMounted, onUnmounted, ref} from 'vue'
|
|
||||||
import {InvestCalendarTimeLine} from "../../wailsjs/go/main/App";
|
|
||||||
import { addMonths, format ,parse} from 'date-fns';
|
|
||||||
import { zhCN } from 'date-fns/locale';
|
|
||||||
|
|
||||||
import {useMessage} from 'naive-ui'
|
|
||||||
import {Star48Filled} from "@vicons/fluent";
|
|
||||||
const today = new Date();
|
|
||||||
const year = today.getFullYear();
|
|
||||||
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
|
|
||||||
const day = String(today.getDate()).padStart(2, '0');
|
|
||||||
|
|
||||||
// 常见格式:YYYY-MM-DD
|
|
||||||
const formattedDate = `${year}-${month}-${day}`;
|
|
||||||
const formattedYM = `${year}-${month}`;
|
|
||||||
const list = ref([])
|
|
||||||
const message=useMessage()
|
|
||||||
|
|
||||||
function goBackToday() {
|
|
||||||
setTimeout(() => {
|
|
||||||
nextTick(
|
|
||||||
() => {
|
|
||||||
const elementById = document.getElementById(formattedDate);
|
|
||||||
if (elementById) {
|
|
||||||
elementById.scrollIntoView({
|
|
||||||
behavior: 'auto',
|
|
||||||
block: 'start'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
InvestCalendarTimeLine(formattedYM).then(res => {
|
|
||||||
list.value = res
|
|
||||||
goBackToday();
|
|
||||||
})
|
|
||||||
})
|
|
||||||
onMounted(()=>{
|
|
||||||
|
|
||||||
})
|
|
||||||
function loadMore(){
|
|
||||||
if (list.value.length>0){
|
|
||||||
let day=parse(list.value[list.value.length-1].date, 'yyyy-MM-dd', new Date())
|
|
||||||
let nextMonth=addMonths(day,1)
|
|
||||||
let ym = format(nextMonth, 'yyyy-MM');
|
|
||||||
console.log(ym)
|
|
||||||
InvestCalendarTimeLine(ym).then(res => {
|
|
||||||
if (res.length==0){
|
|
||||||
message.warning("没有更多数据了")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
list.value.push( ...res)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getweekday(date){
|
|
||||||
let day=parse(date, 'yyyy-MM-dd', new Date())
|
|
||||||
return format(day, 'EEEE', {locale: zhCN})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- <n-timeline size="large" style="text-align: left">-->
|
|
||||||
<!-- <n-timeline-item v-for="item in list" :key="item.date" :title="item.date" type="info" >-->
|
|
||||||
<!-- <n-list>-->
|
|
||||||
<!-- <n-list-item v-for="l in item.list" :key="l.article_id ">-->
|
|
||||||
<!-- <n-text>{{l.title}}</n-text>-->
|
|
||||||
<!-- </n-list-item>-->
|
|
||||||
<!-- </n-list>-->
|
|
||||||
<!-- </n-timeline-item>-->
|
|
||||||
<!-- </n-timeline>-->
|
|
||||||
|
|
||||||
<n-list bordered style="max-height: calc(100vh - 230px);text-align: left;">
|
|
||||||
<n-scrollbar style="max-height: calc(100vh - 230px);" >
|
|
||||||
<n-list-item v-for="(item, index) in list" :id="item.date" :key="item.date">
|
|
||||||
<n-thing :title="item.date+' '+getweekday(item.date)">
|
|
||||||
<n-list :bordered="false" hoverable>
|
|
||||||
<n-list-item v-for="(l,i ) in item.list" :key="l.article_id ">
|
|
||||||
<n-flex justify="space-between">
|
|
||||||
<n-text :type="item.date===formattedDate?'warning':'info'">{{i+1}}# {{l.title}}</n-text>
|
|
||||||
<n-rate v-if="l.like_count>0" readonly :default-value="l.like_count" :count="l.like_count" >
|
|
||||||
<n-icon :component="Star48Filled"/>
|
|
||||||
</n-rate>
|
|
||||||
</n-flex>
|
|
||||||
</n-list-item>
|
|
||||||
</n-list>
|
|
||||||
</n-thing>
|
|
||||||
</n-list-item>
|
|
||||||
<n-list-item v-if="list.length==0">
|
|
||||||
<n-text type="info">没有数据</n-text>
|
|
||||||
</n-list-item>
|
|
||||||
<n-list-item v-else style="text-align: center;">
|
|
||||||
<n-button-group>
|
|
||||||
<n-button strong secondary type="info" @click="loadMore">加载更多</n-button>
|
|
||||||
<n-button strong secondary type="warning" @click="goBackToday">回到今天</n-button>
|
|
||||||
</n-button-group>
|
|
||||||
</n-list-item>
|
|
||||||
</n-scrollbar>
|
|
||||||
</n-list>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -60,7 +60,7 @@ function handleKLine(code,name){
|
|||||||
////console.log("values",values)
|
////console.log("values",values)
|
||||||
let option = {
|
let option = {
|
||||||
title: {
|
title: {
|
||||||
text: name+" "+code,
|
text: name,
|
||||||
left: '20px',
|
left: '20px',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: darkTheme?'#ccc':'#456'
|
color: darkTheme?'#ccc':'#456'
|
||||||
@ -96,7 +96,7 @@ function handleKLine(code,name){
|
|||||||
color: darkTheme?'#ccc':'#456'
|
color: darkTheme?'#ccc':'#456'
|
||||||
},
|
},
|
||||||
formatter: function (params) {//修改鼠标划过显示为中文
|
formatter: function (params) {//修改鼠标划过显示为中文
|
||||||
//console.log("params",params)
|
console.log("params",params)
|
||||||
let currentItemData = _.filter(params, (param) => param.seriesIndex === 0)[0].data;
|
let currentItemData = _.filter(params, (param) => param.seriesIndex === 0)[0].data;
|
||||||
let ma5=_.filter(params, (param) => param.seriesIndex === 1)[0].data;//ma5的值
|
let ma5=_.filter(params, (param) => param.seriesIndex === 1)[0].data;//ma5的值
|
||||||
let ma10=_.filter(params, (param) => param.seriesIndex === 2)[0].data;//ma10的值
|
let ma10=_.filter(params, (param) => param.seriesIndex === 2)[0].data;//ma10的值
|
||||||
@ -354,10 +354,6 @@ function handleKLine(code,name){
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
chart.setOption(option);
|
chart.setOption(option);
|
||||||
|
|
||||||
chart.on('click',{seriesName:'日K'}, function(params) {
|
|
||||||
//console.log("click:",params);
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function calculateMA(dayCount,values) {
|
function calculateMA(dayCount,values) {
|
||||||
|
@ -1,229 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {onBeforeMount, ref} from 'vue'
|
|
||||||
import {LongTigerRank} from "../../wailsjs/go/main/App";
|
|
||||||
import {BrowserOpenURL} from "../../wailsjs/runtime";
|
|
||||||
import {ArrowDownOutline} from "@vicons/ionicons5";
|
|
||||||
import _ from "lodash";
|
|
||||||
import KLineChart from "./KLineChart.vue";
|
|
||||||
import MoneyTrend from "./moneyTrend.vue";
|
|
||||||
import {NButton, NText, useMessage} from "naive-ui";
|
|
||||||
const message = useMessage()
|
|
||||||
|
|
||||||
const lhbList= ref([])
|
|
||||||
const EXPLANATIONs = ref([])
|
|
||||||
|
|
||||||
const today = new Date();
|
|
||||||
const year = today.getFullYear();
|
|
||||||
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
|
|
||||||
const day = String(today.getDate()).padStart(2, '0');
|
|
||||||
|
|
||||||
// 常见格式:YYYY-MM-DD
|
|
||||||
const formattedDate = `${year}-${month}-${day}`;
|
|
||||||
|
|
||||||
const SearchForm= ref({
|
|
||||||
dateValue: formattedDate,
|
|
||||||
EXPLANATION:null,
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
longTiger(formattedDate);
|
|
||||||
})
|
|
||||||
function longTiger_old(date) {
|
|
||||||
if(date) {
|
|
||||||
SearchForm.value.dateValue = date
|
|
||||||
}
|
|
||||||
let loading1=message.loading("正在获取龙虎榜数据...",{
|
|
||||||
duration: 0,
|
|
||||||
})
|
|
||||||
LongTigerRank(date).then(res => {
|
|
||||||
lhbList.value = res
|
|
||||||
loading1.destroy()
|
|
||||||
if (res.length === 0) {
|
|
||||||
message.info("暂无数据,请切换日期")
|
|
||||||
}
|
|
||||||
EXPLANATIONs.value=_.uniqBy(_.map(lhbList.value,function (item){
|
|
||||||
return {
|
|
||||||
label: item['EXPLANATION'],
|
|
||||||
value: item['EXPLANATION'],
|
|
||||||
}
|
|
||||||
}),'label');
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function longTiger(date) {
|
|
||||||
if (date) {
|
|
||||||
SearchForm.value.dateValue = date;
|
|
||||||
}
|
|
||||||
|
|
||||||
let loading1 = message.loading("正在获取龙虎榜数据...", {
|
|
||||||
duration: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchDate = (currentDate, retryCount = 0) => {
|
|
||||||
if (retryCount > 7) { // 防止无限循环,最多尝试7次
|
|
||||||
lhbList.value = [];
|
|
||||||
EXPLANATIONs.value = [];
|
|
||||||
loading1.destroy();
|
|
||||||
message.info("暂无历史数据");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LongTigerRank(currentDate).then(res => {
|
|
||||||
if (res.length === 0) {
|
|
||||||
const previousDate = new Date(currentDate);
|
|
||||||
previousDate.setDate(previousDate.getDate() - 1);
|
|
||||||
|
|
||||||
const year = previousDate.getFullYear();
|
|
||||||
const month = String(previousDate.getMonth() + 1).padStart(2, '0');
|
|
||||||
const day = String(previousDate.getDate()).padStart(2, '0');
|
|
||||||
const prevFormattedDate = `${year}-${month}-${day}`;
|
|
||||||
|
|
||||||
message.info(`当前日期 ${currentDate} 暂无数据,尝试查询前一日:${prevFormattedDate}`);
|
|
||||||
|
|
||||||
SearchForm.value.dateValue = prevFormattedDate;
|
|
||||||
fetchDate(prevFormattedDate, retryCount + 1); // 递归调用
|
|
||||||
} else {
|
|
||||||
lhbList.value = res;
|
|
||||||
loading1.destroy();
|
|
||||||
EXPLANATIONs.value = _.uniqBy(_.map(lhbList.value, function (item) {
|
|
||||||
return {
|
|
||||||
label: item['EXPLANATION'],
|
|
||||||
value: item['EXPLANATION'],
|
|
||||||
};
|
|
||||||
}), 'label');
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
loading1.destroy();
|
|
||||||
message.error("获取数据失败,请重试");
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchDate(date || formattedDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEXPLANATION(value, option){
|
|
||||||
SearchForm.value.EXPLANATION = value
|
|
||||||
if(value){
|
|
||||||
LongTigerRank(SearchForm.value.dateValue).then(res => {
|
|
||||||
lhbList.value=_.filter(res, function(o) { return o['EXPLANATION']===value; });
|
|
||||||
if (res.length === 0) {
|
|
||||||
message.info("暂无数据,请切换日期")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
longTiger(SearchForm.value.dateValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-form :model="SearchForm" >
|
|
||||||
<n-grid :cols="24" :x-gap="24">
|
|
||||||
<n-form-item-gi :span="4" label="日期" path="dateValue" label-placement="left">
|
|
||||||
<n-date-picker v-model:formatted-value="SearchForm.dateValue"
|
|
||||||
value-format="yyyy-MM-dd" type="date" :on-update:value="(v,v2)=>longTiger(v2)"/>
|
|
||||||
|
|
||||||
</n-form-item-gi>
|
|
||||||
<n-form-item-gi :span="8" label="上榜原因" path="EXPLANATION" label-placement="left">
|
|
||||||
<n-select clearable placeholder="上榜原因过滤" v-model:value="SearchForm.EXPLANATION" :options="EXPLANATIONs" :on-update:value="handleEXPLANATION"/>
|
|
||||||
</n-form-item-gi>
|
|
||||||
<n-form-item-gi :span="10" label="" label-placement="left">
|
|
||||||
<n-text type="error">*当天的龙虎榜数据通常在收盘结束后一小时左右更新</n-text>
|
|
||||||
</n-form-item-gi>
|
|
||||||
</n-grid>
|
|
||||||
</n-form>
|
|
||||||
<n-table :single-line="false" striped>
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<n-th>代码</n-th>
|
|
||||||
<!-- <n-th width="90px">日期</n-th>-->
|
|
||||||
<n-th width="60px">名称</n-th>
|
|
||||||
<n-th>收盘价</n-th>
|
|
||||||
<n-th width="60px">涨跌幅</n-th>
|
|
||||||
<n-th>龙虎榜净买额(万)</n-th>
|
|
||||||
<n-th>龙虎榜买入额(万)</n-th>
|
|
||||||
<n-th>龙虎榜卖出额(万)</n-th>
|
|
||||||
<n-th>龙虎榜成交额(万)</n-th>
|
|
||||||
<!-- <n-th>市场总成交额(万)</n-th>-->
|
|
||||||
<!-- <n-th>净买额占总成交比</n-th>-->
|
|
||||||
<!-- <n-th>成交额占总成交比</n-th>-->
|
|
||||||
<n-th width="60px" data-field="TURNOVERRATE">换手率<n-icon :component="ArrowDownOutline" /></n-th>
|
|
||||||
<n-th>流通市值(亿)</n-th>
|
|
||||||
<n-th>上榜原因</n-th>
|
|
||||||
<!-- <n-th>解读</n-th>-->
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="(item, index) in lhbList" :key="index">
|
|
||||||
<n-td>
|
|
||||||
<n-tag :bordered=false type="info">{{ item.SECUCODE.split('.')[1].toLowerCase()+item.SECUCODE.split('.')[0] }}</n-tag>
|
|
||||||
</n-td>
|
|
||||||
<!-- <n-td>
|
|
||||||
{{item.TRADE_DATE.substring(0,10)}}
|
|
||||||
</n-td>-->
|
|
||||||
<n-td>
|
|
||||||
<!-- <n-text :type="item.CHANGE_RATE>0?'error':'success'">{{ item.SECURITY_NAME_ABBR }}</n-text>-->
|
|
||||||
<n-popover trigger="hover" placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<n-button tag="a" text :type="item.CHANGE_RATE>0?'error':'success'" :bordered=false >{{ item.SECURITY_NAME_ABBR }}</n-button>
|
|
||||||
</template>
|
|
||||||
<k-line-chart style="width: 800px" :code="item.SECUCODE.split('.')[1].toLowerCase()+item.SECUCODE.split('.')[0]" :chart-height="500" :name="item.SECURITY_NAME_ABBR" :k-days="20" :dark-theme="true"></k-line-chart>
|
|
||||||
</n-popover>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.CHANGE_RATE>0?'error':'success'">{{ item.CLOSE_PRICE }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.CHANGE_RATE>0?'error':'success'">{{ (item.CHANGE_RATE).toFixed(2) }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<!-- <n-text :type="item.BILLBOARD_NET_AMT>0?'error':'success'">{{ (item.BILLBOARD_NET_AMT/10000).toFixed(2) }}</n-text>-->
|
|
||||||
|
|
||||||
|
|
||||||
<n-popover trigger="hover" placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<n-button tag="a" text :type="item.BILLBOARD_NET_AMT>0?'error':'success'" :bordered=false >{{ (item.BILLBOARD_NET_AMT/10000).toFixed(2) }}</n-button>
|
|
||||||
</template>
|
|
||||||
<money-trend :code="item.SECUCODE.split('.')[1].toLowerCase()+item.SECUCODE.split('.')[0]" :name="item.SECURITY_NAME_ABBR" :days="360" :dark-theme="true" :chart-height="500" style="width: 800px"></money-trend>
|
|
||||||
</n-popover>
|
|
||||||
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="'error'">{{ (item.BILLBOARD_BUY_AMT/10000).toFixed(2) }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="'success'">{{ (item.BILLBOARD_SELL_AMT/10000).toFixed(2) }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="'info'">{{ (item.BILLBOARD_DEAL_AMT/10000).toFixed(2) }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
<!-- <n-td>-->
|
|
||||||
<!-- <n-text :type="'info'">{{ (item.ACCUM_AMOUNT/10000).toFixed(2) }}</n-text>-->
|
|
||||||
<!-- </n-td>-->
|
|
||||||
<!-- <n-td>-->
|
|
||||||
<!-- <n-text :type="item.DEAL_NET_RATIO>0?'error':'success'">{{ (item.DEAL_NET_RATIO).toFixed(2) }}%</n-text>-->
|
|
||||||
<!-- </n-td>-->
|
|
||||||
<!-- <n-td>-->
|
|
||||||
<!-- <n-text :type="'info'">{{ (item.DEAL_AMOUNT_RATIO).toFixed(2) }}%</n-text>-->
|
|
||||||
<!-- </n-td>-->
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="'info'">{{ (item.TURNOVERRATE).toFixed(2) }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="'info'">{{ (item.FREE_MARKET_CAP/100000000).toFixed(2) }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="'info'">{{ item.EXPLANATION }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
<!-- <n-td>
|
|
||||||
<n-text :type="item.CHANGE_RATE>0?'error':'success'">{{ item.EXPLAIN }}</n-text>
|
|
||||||
</n-td>-->
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,126 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {h, onBeforeMount, onMounted, onUnmounted, ref} from 'vue'
|
|
||||||
import {SearchStock} from "../../wailsjs/go/main/App";
|
|
||||||
import {useMessage, NText, NTag} from 'naive-ui'
|
|
||||||
const message = useMessage()
|
|
||||||
const search = ref('科技股;换手率连续3日大于2')
|
|
||||||
const columns = ref([])
|
|
||||||
const dataList = ref([])
|
|
||||||
|
|
||||||
function Search() {
|
|
||||||
const loading = message.loading("正在获取选股数据...", {duration: 0});
|
|
||||||
SearchStock(search.value).then(res => {
|
|
||||||
loading.destroy()
|
|
||||||
//console.log(res)
|
|
||||||
if(res.code==100){
|
|
||||||
message.success(res.msg)
|
|
||||||
columns.value=res.data.result.columns.filter(item=>!item.hiddenNeed&&(item.title!="市场码"&&item.title!="市场简称")).map(item=>{
|
|
||||||
|
|
||||||
if(item.children){
|
|
||||||
return {
|
|
||||||
title:item.title+(item.unit?'['+item.unit+']':''),
|
|
||||||
key:item.key,
|
|
||||||
resizable: true,
|
|
||||||
minWidth:200,
|
|
||||||
ellipsis: {
|
|
||||||
tooltip: true
|
|
||||||
},
|
|
||||||
children:item.children.filter(item=>!item.hiddenNeed).map(item=>{
|
|
||||||
return {
|
|
||||||
title:item.dateMsg,
|
|
||||||
key:item.key,
|
|
||||||
minWidth:100,
|
|
||||||
resizable: true,
|
|
||||||
ellipsis: {
|
|
||||||
tooltip: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
return {
|
|
||||||
title:item.title+(item.unit?'['+item.unit+']':''),
|
|
||||||
key:item.key,
|
|
||||||
resizable: true,
|
|
||||||
minWidth:100,
|
|
||||||
ellipsis: {
|
|
||||||
tooltip: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
dataList.value=res.data.result.dataList
|
|
||||||
}else {
|
|
||||||
message.error(res.msg)
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
message.error(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
function isNumeric(value) {
|
|
||||||
return !isNaN(parseFloat(value)) && isFinite(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
Search()
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-flex>
|
|
||||||
<n-input-group>
|
|
||||||
<n-input v-model:value="search" placeholder="请输入选股指标或者要求" />
|
|
||||||
<n-button type="success" @click="Search">搜索A股</n-button>
|
|
||||||
</n-input-group>
|
|
||||||
</n-flex>
|
|
||||||
<!-- <n-table striped size="small">-->
|
|
||||||
<!-- <n-thead>-->
|
|
||||||
<!-- <n-tr>-->
|
|
||||||
<!-- <n-th v-for="item in columns">{{item.title}}</n-th>-->
|
|
||||||
<!-- </n-tr>-->
|
|
||||||
<!-- </n-thead>-->
|
|
||||||
<!-- <n-tbody>-->
|
|
||||||
<!-- <n-tr v-for="(item,index) in dataList">-->
|
|
||||||
<!-- <n-td v-for="d in columns">{{item[d.key]}}</n-td>-->
|
|
||||||
<!-- </n-tr>-->
|
|
||||||
<!-- </n-tbody>-->
|
|
||||||
<!-- </n-table>-->
|
|
||||||
<n-data-table
|
|
||||||
:max-height="'calc(100vh - 285px)'"
|
|
||||||
size="small"
|
|
||||||
:columns="columns"
|
|
||||||
:data="dataList"
|
|
||||||
:pagination="false"
|
|
||||||
:scroll-x="1800"
|
|
||||||
:render-cell="(value, rowData, column) => {
|
|
||||||
|
|
||||||
if(column.key=='SECURITY_CODE'||column.key=='SERIAL'){
|
|
||||||
return h(NText, { type: 'info',border: false }, { default: () => `${value}` })
|
|
||||||
}
|
|
||||||
if (isNumeric(value)) {
|
|
||||||
let type='info';
|
|
||||||
if (Number(value)<0){
|
|
||||||
type='success';
|
|
||||||
}
|
|
||||||
if(Number(value)>=0&&Number(value)<=5){
|
|
||||||
type='warning';
|
|
||||||
}
|
|
||||||
if (Number(value)>5){
|
|
||||||
type='error';
|
|
||||||
}
|
|
||||||
return h(NText, { type: type }, { default: () => `${value}` })
|
|
||||||
}else{
|
|
||||||
if(column.key=='SECURITY_SHORT_NAME'){
|
|
||||||
return h(NTag, { type: 'info',bordered: false }, { default: () => `${value}` })
|
|
||||||
}else{
|
|
||||||
return h(NText, { type: 'info' }, { default: () => `${value}` })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,148 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {onBeforeMount, ref} from 'vue'
|
|
||||||
import {GetStockList, StockNotice} from "../../wailsjs/go/main/App";
|
|
||||||
import {BrowserOpenURL} from "../../wailsjs/runtime";
|
|
||||||
import {RefreshCircleSharp} from "@vicons/ionicons5";
|
|
||||||
import _ from "lodash";
|
|
||||||
import KLineChart from "./KLineChart.vue";
|
|
||||||
import MoneyTrend from "./moneyTrend.vue";
|
|
||||||
import {useMessage} from "naive-ui";
|
|
||||||
|
|
||||||
const {stockCode}=defineProps(
|
|
||||||
{
|
|
||||||
stockCode: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const list = ref([])
|
|
||||||
const options = ref([])
|
|
||||||
const message=useMessage()
|
|
||||||
function getNotice(stockCodes) {
|
|
||||||
StockNotice(stockCodes).then(result => {
|
|
||||||
console.log(result)
|
|
||||||
list.value = result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount (()=>{
|
|
||||||
//message.info("正在获取数据"+stockCode)
|
|
||||||
getNotice(stockCode);
|
|
||||||
})
|
|
||||||
|
|
||||||
function findStockList(query){
|
|
||||||
if (query){
|
|
||||||
GetStockList(query).then(result => {
|
|
||||||
options.value=result.map(item => {
|
|
||||||
return {
|
|
||||||
label: item.name+" - "+item.ts_code,
|
|
||||||
value: item.ts_code
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
getNotice("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function handleSearch(value) {
|
|
||||||
getNotice(value)
|
|
||||||
}
|
|
||||||
function openWin(code) {
|
|
||||||
BrowserOpenURL("https://pdf.dfcfw.com/pdf/H2_"+code+"_1.pdf?1750092081000.pdf")
|
|
||||||
}
|
|
||||||
function getTypeColor(name){
|
|
||||||
if(name.includes("质押")||name.includes("冻结")||name.includes("解冻")||name.includes("解押")||name.includes("解禁")){
|
|
||||||
return "error"
|
|
||||||
}
|
|
||||||
if(name.includes("异常")||name.includes("减持")||name.includes("增发")||name.includes("重大")){
|
|
||||||
return "error"
|
|
||||||
}
|
|
||||||
if(name.includes("季度报告")||name.includes("年度报告")||name.includes("澄清公告")||name.includes("风险")){
|
|
||||||
return "error"
|
|
||||||
}
|
|
||||||
if(name.includes("终止")||name.includes("复牌")||name.includes("停牌")||name.includes("退市")){
|
|
||||||
return "error"
|
|
||||||
}
|
|
||||||
if(name.includes("破产")||name.includes("清算")){
|
|
||||||
return "error"
|
|
||||||
}
|
|
||||||
if(name.includes("回购")||name.includes("重组")||name.includes("诉讼")||name.includes("仲裁")||name.includes("转让")||name.includes("收购")){
|
|
||||||
return "warning"
|
|
||||||
}
|
|
||||||
if(name.includes("调研")||name.includes("募集")){
|
|
||||||
return "warning"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "info"
|
|
||||||
|
|
||||||
}
|
|
||||||
function getmMarketCode(market,code) {
|
|
||||||
if(market==="0"){
|
|
||||||
return "sz"+code
|
|
||||||
}else if(market==="1"){
|
|
||||||
return "sh"+code
|
|
||||||
}else if(market==="2"){
|
|
||||||
return "bj"+code
|
|
||||||
}else if(market==="3"){
|
|
||||||
return "hk"+code
|
|
||||||
}else{
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-card>
|
|
||||||
<n-auto-complete :options="options" placeholder="请输入A股名称或者代码" clearable filterable :on-select="handleSearch" :on-update:value="findStockList" />
|
|
||||||
</n-card>
|
|
||||||
<n-table striped size="small">
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<n-th>股票代码</n-th>
|
|
||||||
<n-th>股票名称</n-th>
|
|
||||||
<n-th>公告标题</n-th>
|
|
||||||
<n-th>公告类型</n-th>
|
|
||||||
<n-th>公告日期</n-th>
|
|
||||||
<n-th><n-flex>数据更新时间<n-icon @click="getNotice('')" color="#409EFF" :size="20" :component="RefreshCircleSharp"/></n-flex></n-th>
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="item in list" :key="item.art_code">
|
|
||||||
<n-td>
|
|
||||||
<n-popover trigger="hover" placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<n-tag type="info" :bordered="false">{{item.codes[0].stock_code }}</n-tag>
|
|
||||||
</template>
|
|
||||||
<money-trend style="width: 800px" :code="getmMarketCode(item.codes[0].market_code,item.codes[0].stock_code)" :name="item.codes[0].short_name" :days="360" :dark-theme="true" :chart-height="500"></money-trend>
|
|
||||||
</n-popover>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-popover trigger="hover" placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<n-tag type="info" :bordered="false">{{item.codes[0].short_name }}</n-tag>
|
|
||||||
</template>
|
|
||||||
<k-line-chart style="width: 800px" :code="getmMarketCode(item.codes[0].market_code,item.codes[0].stock_code)" :chart-height="500" :name="item.codes[0].short_name" :k-days="20" :dark-theme="true"></k-line-chart>
|
|
||||||
</n-popover>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-a type="info" @click="openWin(item.art_code)"><n-text :type="getTypeColor(item.columns[0].column_name)"> {{item.title}}</n-text></n-a>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="getTypeColor(item.columns[0].column_name)">{{item.columns[0].column_name }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-tag type="info">{{item.notice_date.substring(0,10) }}</n-tag>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-tag type="info">{{item.display_time.substring(0,19)}}</n-tag>
|
|
||||||
</n-td>
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,136 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {onBeforeMount, ref} from 'vue'
|
|
||||||
import {GetStockList, StockResearchReport} from "../../wailsjs/go/main/App";
|
|
||||||
import {ArrowDownOutline, CaretDown, CaretUp, PulseOutline, Refresh, RefreshCircleSharp,} from "@vicons/ionicons5";
|
|
||||||
|
|
||||||
import KLineChart from "./KLineChart.vue";
|
|
||||||
import MoneyTrend from "./moneyTrend.vue";
|
|
||||||
import {useMessage} from "naive-ui";
|
|
||||||
import {BrowserOpenURL} from "../../wailsjs/runtime";
|
|
||||||
|
|
||||||
const {stockCode}=defineProps(
|
|
||||||
{
|
|
||||||
stockCode: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const message=useMessage()
|
|
||||||
const list = ref([])
|
|
||||||
|
|
||||||
const options = ref([])
|
|
||||||
|
|
||||||
function getStockResearchReport(value) {
|
|
||||||
StockResearchReport(value).then(result => {
|
|
||||||
//console.log(result)
|
|
||||||
list.value = result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(()=>{
|
|
||||||
getStockResearchReport(stockCode);
|
|
||||||
})
|
|
||||||
|
|
||||||
function ratingChangeName(ratingChange){
|
|
||||||
if(ratingChange===0){
|
|
||||||
return '调高'
|
|
||||||
}else if(ratingChange===1){
|
|
||||||
return '调低'
|
|
||||||
}else if(ratingChange===2){
|
|
||||||
return '首次'
|
|
||||||
}else if(ratingChange===3){
|
|
||||||
return '维持'
|
|
||||||
}else if (ratingChange===4){
|
|
||||||
return '无变化'
|
|
||||||
}else{
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getmMarketCode(market,code) {
|
|
||||||
if(market==="SHENZHEN"){
|
|
||||||
return "sz"+code
|
|
||||||
}else if(market==="SHANGHAI"){
|
|
||||||
return "sh"+code
|
|
||||||
}else if(market==="BEIJING"){
|
|
||||||
return "bj"+code
|
|
||||||
}else if(market==="HONGKONG"){
|
|
||||||
return "hk"+code
|
|
||||||
}else{
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function openWin(code) {
|
|
||||||
BrowserOpenURL("https://pdf.dfcfw.com/pdf/H3_"+code+"_1.pdf?1749744888000.pdf")
|
|
||||||
}
|
|
||||||
|
|
||||||
function findStockList(query){
|
|
||||||
if (query){
|
|
||||||
GetStockList(query).then(result => {
|
|
||||||
options.value=result.map(item => {
|
|
||||||
return {
|
|
||||||
label: item.name+" - "+item.ts_code,
|
|
||||||
value: item.ts_code
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
getStockResearchReport('')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function handleSearch(value) {
|
|
||||||
getStockResearchReport(value)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-card>
|
|
||||||
<n-auto-complete :options="options" placeholder="请输入A股名称或者代码" clearable filterable :on-select="handleSearch" :on-update:value="findStockList" />
|
|
||||||
</n-card>
|
|
||||||
<n-table striped size="small">
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<!-- <n-th>代码</n-th>-->
|
|
||||||
<n-th>名称</n-th>
|
|
||||||
<n-th>行业</n-th>
|
|
||||||
<n-th>标题</n-th>
|
|
||||||
<n-th>东财评级</n-th>
|
|
||||||
<n-th>评级变动</n-th>
|
|
||||||
<n-th>机构评级</n-th>
|
|
||||||
<n-th>分析师</n-th>
|
|
||||||
<n-th>机构</n-th>
|
|
||||||
<n-th> <n-flex justify="space-between">日期<n-icon @click="getStockResearchReport" color="#409EFF" :size="20" :component="RefreshCircleSharp"/></n-flex></n-th>
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="item in list" :key="item.infoCode">
|
|
||||||
<!-- <n-td>{{item.stockCode}}</n-td>-->
|
|
||||||
<n-td :title="item.stockCode">
|
|
||||||
<n-popover trigger="hover" placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<n-tag type="info" :bordered="false">{{item.stockName}}</n-tag>
|
|
||||||
</template>
|
|
||||||
<k-line-chart style="width: 800px" :code="getmMarketCode(item.market,item.stockCode)" :chart-height="500" :name="item.stockName" :k-days="20" :dark-theme="true"></k-line-chart>
|
|
||||||
</n-popover>
|
|
||||||
</n-td>
|
|
||||||
<n-td><n-tag type="info" :bordered="false">{{item.indvInduName}}</n-tag></n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-a type="info" @click="openWin(item.infoCode)">{{item.title}}</n-a>
|
|
||||||
</n-td>
|
|
||||||
<n-td><n-text :type="item.emRatingName==='增持'?'error':'info'">
|
|
||||||
{{item.emRatingName}}
|
|
||||||
</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.ratingChange===0?'error':'info'">{{ratingChangeName(item.ratingChange)}}</n-text></n-td>
|
|
||||||
<n-td>{{item.sRatingName}}</n-td>
|
|
||||||
<n-td>{{item.researcher}}</n-td>
|
|
||||||
<n-td>{{item.orgSName}}</n-td>
|
|
||||||
<n-td>{{item.publishDate.substring(0,10)}}</n-td>
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -4,7 +4,7 @@
|
|||||||
import 'md-editor-v3/lib/preview.css';
|
import 'md-editor-v3/lib/preview.css';
|
||||||
import {h, onBeforeUnmount, onMounted, ref} from 'vue';
|
import {h, onBeforeUnmount, onMounted, ref} from 'vue';
|
||||||
import {CheckUpdate, GetVersionInfo} from "../../wailsjs/go/main/App";
|
import {CheckUpdate, GetVersionInfo} from "../../wailsjs/go/main/App";
|
||||||
import {EventsOff, EventsOn} from "../../wailsjs/runtime";
|
import {EventsOn} from "../../wailsjs/runtime";
|
||||||
import {NAvatar, NButton, useNotification} from "naive-ui";
|
import {NAvatar, NButton, useNotification} from "naive-ui";
|
||||||
const updateLog = ref('');
|
const updateLog = ref('');
|
||||||
const versionInfo = ref('');
|
const versionInfo = ref('');
|
||||||
@ -25,7 +25,6 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
notify.destroyAll()
|
notify.destroyAll()
|
||||||
EventsOff("updateVersion")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
EventsOn("updateVersion",async (msg) => {
|
EventsOn("updateVersion",async (msg) => {
|
||||||
@ -44,8 +43,8 @@ EventsOn("updateVersion",async (msg) => {
|
|||||||
|
|
||||||
const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
|
||||||
//console.log("GitHub UTC 时间:", utcDate);
|
console.log("GitHub UTC 时间:", utcDate);
|
||||||
//console.log("转换后的本地时间:", formattedDate);
|
console.log("转换后的本地时间:", formattedDate);
|
||||||
notify.info({
|
notify.info({
|
||||||
avatar: () =>
|
avatar: () =>
|
||||||
h(NAvatar, {
|
h(NAvatar, {
|
||||||
@ -135,7 +134,6 @@ EventsOn("updateVersion",async (msg) => {
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
感谢以下开发者:
|
感谢以下开发者:
|
||||||
<a href="https://github.com/CodeNoobLH" target="_blank">浓睡不消残酒</a><n-divider vertical />
|
|
||||||
<a href="https://github.com/gnim2600" target="_blank">@gnim2600</a><n-divider vertical />
|
<a href="https://github.com/gnim2600" target="_blank">@gnim2600</a><n-divider vertical />
|
||||||
<a href="https://github.com/XXXiaohuayanGGG" target="_blank">@XXXiaohuayanGGG</a><n-divider vertical />
|
<a href="https://github.com/XXXiaohuayanGGG" target="_blank">@XXXiaohuayanGGG</a><n-divider vertical />
|
||||||
<a href="https://github.com/2lovecode" target="_blank">@2lovecode</a><n-divider vertical />
|
<a href="https://github.com/2lovecode" target="_blank">@2lovecode</a><n-divider vertical />
|
||||||
|
@ -47,7 +47,7 @@ onBeforeMount(()=>{
|
|||||||
})
|
})
|
||||||
GetFollowedFund().then(result => {
|
GetFollowedFund().then(result => {
|
||||||
followList.value = result
|
followList.value = result
|
||||||
//console.log("followList",followList.value)
|
console.log("followList",followList.value)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ onMounted(() => {
|
|||||||
//ws.value = new WebSocket('ws://localhost:16688/ws'); // 替换为你的 WebSocket 服务器地址
|
//ws.value = new WebSocket('ws://localhost:16688/ws'); // 替换为你的 WebSocket 服务器地址
|
||||||
|
|
||||||
ws.value.onopen = () => {
|
ws.value.onopen = () => {
|
||||||
//console.log('WebSocket 连接已打开');
|
console.log('WebSocket 连接已打开');
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.value.onmessage = (event) => {
|
ws.value.onmessage = (event) => {
|
||||||
@ -74,13 +74,13 @@ onMounted(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ws.value.onclose = () => {
|
ws.value.onclose = () => {
|
||||||
//console.log('WebSocket 连接已关闭');
|
console.log('WebSocket 连接已关闭');
|
||||||
};
|
};
|
||||||
|
|
||||||
ticker.value=setInterval(() => {
|
ticker.value=setInterval(() => {
|
||||||
GetFollowedFund().then(result => {
|
GetFollowedFund().then(result => {
|
||||||
followList.value = result
|
followList.value = result
|
||||||
//console.log("followList",followList.value)
|
console.log("followList",followList.value)
|
||||||
})
|
})
|
||||||
}, 1000*60)
|
}, 1000*60)
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ function AddFund(){
|
|||||||
message.success("关注成功")
|
message.success("关注成功")
|
||||||
GetFollowedFund().then(result => {
|
GetFollowedFund().then(result => {
|
||||||
followList.value = result
|
followList.value = result
|
||||||
//console.log("followList",followList.value)
|
console.log("followList",followList.value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -114,7 +114,7 @@ function unFollow(code){
|
|||||||
message.success("取消关注成功")
|
message.success("取消关注成功")
|
||||||
GetFollowedFund().then(result => {
|
GetFollowedFund().then(result => {
|
||||||
followList.value = result
|
followList.value = result
|
||||||
//console.log("followList",followList.value)
|
console.log("followList",followList.value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,94 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
|
|
||||||
import {CaretDown, CaretUp, RefreshCircleOutline} from "@vicons/ionicons5";
|
|
||||||
import {NText,useMessage} from "naive-ui";
|
|
||||||
import {onBeforeUnmount, onMounted, onUnmounted, ref} from "vue";
|
|
||||||
import {GetIndustryMoneyRankSina} from "../../wailsjs/go/main/App";
|
|
||||||
import KLineChart from "./KLineChart.vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
headerTitle: {
|
|
||||||
type: String,
|
|
||||||
default: '行业资金排名(净流入)'
|
|
||||||
},
|
|
||||||
fenlei: {
|
|
||||||
type: String,
|
|
||||||
default: '0'
|
|
||||||
},
|
|
||||||
sort: {
|
|
||||||
type: String,
|
|
||||||
default: 'netamount'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const message = useMessage()
|
|
||||||
const dataList= ref([])
|
|
||||||
const sort = ref(props.sort)
|
|
||||||
const fenlei= ref(props.fenlei)
|
|
||||||
|
|
||||||
const interval = ref(null)
|
|
||||||
onMounted(()=>{
|
|
||||||
sort.value=props.sort
|
|
||||||
fenlei.value=props.fenlei
|
|
||||||
GetRankData()
|
|
||||||
interval.value=setInterval(()=>{
|
|
||||||
GetRankData()
|
|
||||||
},1000*60)
|
|
||||||
})
|
|
||||||
onBeforeUnmount(()=>{
|
|
||||||
clearInterval(interval.value)
|
|
||||||
})
|
|
||||||
function GetRankData(){
|
|
||||||
message.loading("正在刷新数据...")
|
|
||||||
GetIndustryMoneyRankSina(fenlei.value,sort.value).then(result => {
|
|
||||||
if(result.length>0){
|
|
||||||
dataList.value = result
|
|
||||||
//console.log(result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-table striped size="small">
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<n-th>板块名称</n-th>
|
|
||||||
<n-th>涨跌幅</n-th>
|
|
||||||
<n-th>流入资金/万</n-th>
|
|
||||||
<n-th>流出资金/万</n-th>
|
|
||||||
<n-th>净流入/万<n-icon v-if="sort==='0'" :component="CaretDown"/><n-icon v-if="sort==='1'" :component="CaretUp"/></n-th>
|
|
||||||
<n-th>净流入率</n-th>
|
|
||||||
<n-th>领涨股</n-th>
|
|
||||||
<n-th>涨跌幅</n-th>
|
|
||||||
<n-th>最新价</n-th>
|
|
||||||
<n-th>净流入率</n-th>
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="item in dataList" :key="item.category">
|
|
||||||
<n-td><n-tag :bordered=false type="info">{{item.name}}</n-tag></n-td>
|
|
||||||
<n-td> <n-text :type="item.avg_changeratio>0?'error':'success'">{{(item.avg_changeratio*100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
<n-td><n-text type="info">{{(item.inamount/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td><n-text type="info">{{(item.outamount/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.netamount>0?'error':'success'">{{(item.netamount/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.ratioamount>0?'error':'success'">{{(item.ratioamount*100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
<n-td>
|
|
||||||
<!-- <n-text type="info">{{item.ts_name}}</n-text>-->
|
|
||||||
<n-popover trigger="hover" placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<n-button tag="a" text :type="item.ts_changeratio>0?'error':'success'" :bordered=false >{{ item.ts_name }}</n-button>
|
|
||||||
</template>
|
|
||||||
<k-line-chart style="width: 800px" :code="item.ts_symbol" :chart-height="500" :name="item.ts_name" :k-days="20" :dark-theme="true"></k-line-chart>
|
|
||||||
</n-popover>
|
|
||||||
</n-td>
|
|
||||||
<n-td><n-text :type="item.ts_changeratio>0?'error':'success'">{{(item.ts_changeratio*100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
<n-td><n-text type="info">{{item.ts_trade}}</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.ts_ratioamount>0?'error':'success'">{{(item.ts_ratioamount*100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,39 +1,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {computed, h, onBeforeMount, onBeforeUnmount, ref} from 'vue'
|
import {computed, h, onBeforeMount, ref} from 'vue'
|
||||||
import {
|
import {
|
||||||
GetAIResponseResult,
|
GetAIResponseResult,
|
||||||
GetConfig,
|
GetConfig, GetPromptTemplates,
|
||||||
GetIndustryRank,
|
|
||||||
GetPromptTemplates,
|
|
||||||
GetTelegraphList,
|
GetTelegraphList,
|
||||||
GlobalStockIndexes,
|
GlobalStockIndexes,
|
||||||
ReFleshTelegraphList,
|
SaveAIResponseResult, SaveAsMarkdown, ShareAnalysis,
|
||||||
SaveAIResponseResult,
|
|
||||||
SaveAsMarkdown,
|
|
||||||
ShareAnalysis,
|
|
||||||
SummaryStockNews
|
SummaryStockNews
|
||||||
} from "../../wailsjs/go/main/App";
|
} from "../../wailsjs/go/main/App";
|
||||||
import {EventsOff, EventsOn} from "../../wailsjs/runtime";
|
import {EventsOn} from "../../wailsjs/runtime";
|
||||||
import NewsList from "./newsList.vue";
|
import NewsList from "./newsList.vue";
|
||||||
import KLineChart from "./KLineChart.vue";
|
import KLineChart from "./KLineChart.vue";
|
||||||
import { CaretDown, CaretUp, PulseOutline,} from "@vicons/ionicons5";
|
import {Add, ChatboxOutline, PulseOutline,} from "@vicons/ionicons5";
|
||||||
import {NAvatar, NButton, NFlex, NText, useMessage, useNotification} from "naive-ui";
|
import {NAvatar, NButton, NFlex, NText, useMessage, useNotification} from "naive-ui";
|
||||||
import {MdPreview} from "md-editor-v3";
|
import {ExportPDF} from "@vavt/v3-extension";
|
||||||
import {useRoute} from 'vue-router'
|
import {MdEditor, MdPreview} from "md-editor-v3";
|
||||||
import RankTable from "./rankTable.vue";
|
|
||||||
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";
|
|
||||||
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');
|
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
@ -42,6 +23,7 @@ const panelHeight = ref(window.innerHeight - 240)
|
|||||||
|
|
||||||
const telegraphList = ref([])
|
const telegraphList = ref([])
|
||||||
const sinaNewsList = ref([])
|
const sinaNewsList = ref([])
|
||||||
|
|
||||||
const common = ref([])
|
const common = ref([])
|
||||||
const america = ref([])
|
const america = ref([])
|
||||||
const europe = ref([])
|
const europe = ref([])
|
||||||
@ -64,12 +46,6 @@ const loading = ref(true)
|
|||||||
const sysPromptOptions=ref([])
|
const sysPromptOptions=ref([])
|
||||||
const userPromptOptions=ref([])
|
const userPromptOptions=ref([])
|
||||||
const promptTemplates=ref([])
|
const promptTemplates=ref([])
|
||||||
const industryRanks = ref([])
|
|
||||||
const sort = ref("0")
|
|
||||||
const nowTab = ref("市场快讯")
|
|
||||||
const indexInterval = ref(null)
|
|
||||||
const indexIndustryRank = ref(null)
|
|
||||||
const stockCode= ref('')
|
|
||||||
|
|
||||||
function getIndex() {
|
function getIndex() {
|
||||||
GlobalStockIndexes().then((res) => {
|
GlobalStockIndexes().then((res) => {
|
||||||
@ -82,11 +58,7 @@ function getIndex() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
nowTab.value = route.query.name
|
|
||||||
stockCode.value = route.query.stockCode
|
|
||||||
GetConfig().then(result => {
|
GetConfig().then(result => {
|
||||||
summaryBTN.value= result.openAiEnable
|
summaryBTN.value= result.openAiEnable
|
||||||
darkTheme.value = result.darkTheme
|
darkTheme.value = result.darkTheme
|
||||||
@ -104,29 +76,13 @@ onBeforeMount(() => {
|
|||||||
sinaNewsList.value = res
|
sinaNewsList.value = res
|
||||||
})
|
})
|
||||||
getIndex();
|
getIndex();
|
||||||
industryRank();
|
|
||||||
indexInterval.value = setInterval(() => {
|
setInterval(() => {
|
||||||
getIndex()
|
getIndex()
|
||||||
}, 3000)
|
}, 3000)
|
||||||
|
|
||||||
indexIndustryRank.value = setInterval(() => {
|
|
||||||
industryRank()
|
|
||||||
}, 1000 * 10)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
EventsOff("changeMarketTab")
|
|
||||||
EventsOff("newTelegraph")
|
|
||||||
EventsOff("newSinaNews")
|
|
||||||
EventsOff("summaryStockNews")
|
|
||||||
clearInterval(indexInterval.value)
|
|
||||||
clearInterval(indexIndustryRank.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
EventsOn("changeMarketTab", async (msg) => {
|
|
||||||
//message.info(msg.name)
|
|
||||||
updateTab(msg.name)
|
|
||||||
})
|
|
||||||
|
|
||||||
EventsOn("newTelegraph", (data) => {
|
EventsOn("newTelegraph", (data) => {
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
@ -149,7 +105,7 @@ window.onresize = () => {
|
|||||||
function getAreaName(code){
|
function getAreaName(code){
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case "america":
|
case "america":
|
||||||
return "美洲"
|
return "美国"
|
||||||
case "europe":
|
case "europe":
|
||||||
return "欧洲"
|
return "欧洲"
|
||||||
case "asia":
|
case "asia":
|
||||||
@ -160,35 +116,12 @@ function getAreaName(code) {
|
|||||||
return "其他"
|
return "其他"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeIndustryRankSort() {
|
|
||||||
if (sort.value === "0") {
|
|
||||||
sort.value = "1"
|
|
||||||
} else {
|
|
||||||
sort.value = "0"
|
|
||||||
}
|
|
||||||
industryRank()
|
|
||||||
}
|
|
||||||
|
|
||||||
function industryRank() {
|
|
||||||
|
|
||||||
GetIndustryRank(sort.value, 150).then(result => {
|
|
||||||
if (result.length > 0) {
|
|
||||||
//console.log(result)
|
|
||||||
industryRanks.value = result
|
|
||||||
} else {
|
|
||||||
message.info("暂无数据")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function reAiSummary(){
|
function reAiSummary(){
|
||||||
aiSummary.value=""
|
aiSummary.value=""
|
||||||
summaryModal.value = true
|
summaryModal.value = true
|
||||||
loading.value = true
|
loading.value = true
|
||||||
SummaryStockNews(question.value,sysPromptId.value)
|
SummaryStockNews(question.value,sysPromptId.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAiSummary(){
|
function getAiSummary(){
|
||||||
summaryModal.value = true
|
summaryModal.value = true
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@ -218,7 +151,6 @@ function getAiSummary() {
|
|||||||
|
|
||||||
function updateTab(name) {
|
function updateTab(name) {
|
||||||
summaryBTN.value = (name === "市场快讯");
|
summaryBTN.value = (name === "市场快讯");
|
||||||
nowTab.value = name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventsOn("summaryStockNews",async (msg) => {
|
EventsOn("summaryStockNews",async (msg) => {
|
||||||
@ -259,13 +191,11 @@ async function copyToClipboard() {
|
|||||||
message.error('复制失败: ' + err);
|
message.error('复制失败: ' + err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveAsMarkdown(){
|
function saveAsMarkdown(){
|
||||||
SaveAsMarkdown('市场资讯','市场资讯').then(result => {
|
SaveAsMarkdown('市场资讯','市场资讯').then(result => {
|
||||||
message.success(result)
|
message.success(result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function share(){
|
function share(){
|
||||||
ShareAnalysis('市场资讯','市场资讯').then(msg => {
|
ShareAnalysis('市场资讯','市场资讯').then(msg => {
|
||||||
//message.info(msg)
|
//message.info(msg)
|
||||||
@ -289,30 +219,18 @@ function share() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function ReFlesh(source) {
|
|
||||||
//console.log("ReFlesh:", source)
|
|
||||||
ReFleshTelegraphList(source).then(res => {
|
|
||||||
if (source === "财联社电报") {
|
|
||||||
telegraphList.value = res
|
|
||||||
}
|
|
||||||
if (source === "新浪财经") {
|
|
||||||
sinaNewsList.value = res
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-card>
|
<n-card>
|
||||||
<n-tabs type="line" animated @update-value="updateTab" :value="nowTab">
|
<n-tabs type="line" animated @update-value="updateTab">
|
||||||
<n-tab-pane name="市场快讯" tab="市场快讯" >
|
<n-tab-pane name="市场快讯" tab="市场快讯" >
|
||||||
<n-grid :cols="2" :y-gap="0">
|
<n-grid :cols="2" :y-gap="0">
|
||||||
<n-gi>
|
<n-gi>
|
||||||
<news-list :newsList="telegraphList" :header-title="'财联社电报'" @update:message="ReFlesh"></news-list>
|
<news-list :newsList="telegraphList" :header-title="'财联社电报'"></news-list>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-gi>
|
<n-gi>
|
||||||
<news-list :newsList="sinaNewsList" :header-title="'新浪财经'" @update:message="ReFlesh"></news-list>
|
<news-list :newsList="sinaNewsList" :header-title="'新浪财经'"></news-list>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
</n-grid>
|
</n-grid>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
@ -329,16 +247,11 @@ function ReFlesh(source) {
|
|||||||
<n-grid :cols="3" :y-gap="0">
|
<n-grid :cols="3" :y-gap="0">
|
||||||
<n-gi>
|
<n-gi>
|
||||||
|
|
||||||
<n-text :type="item.zdf>0?'error':'success'">
|
<n-text :type="item.zdf>0?'error':'success'"><n-image :src="item.img" width="20"/> {{ item.name }}</n-text>
|
||||||
<n-image :src="item.img" width="20"/> {{ item.name }}
|
|
||||||
</n-text>
|
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-gi>
|
<n-gi>
|
||||||
<n-text :type="item.zdf>0?'error':'success'">{{ item.zxj }}</n-text>
|
<n-text :type="item.zdf>0?'error':'success'">{{ item.zxj }}</n-text>
|
||||||
<n-text :type="item.zdf>0?'error':'success'">
|
<n-text :type="item.zdf>0?'error':'success'"><n-number-animation :precision="2" :from="0" :to="item.zdf" />%</n-text>
|
||||||
<n-number-animation :precision="2" :from="0" :to="item.zdf"/>
|
|
||||||
%
|
|
||||||
</n-text>
|
|
||||||
|
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-gi>
|
<n-gi>
|
||||||
@ -413,195 +326,11 @@ function ReFlesh(source) {
|
|||||||
<k-line-chart code="usYINN.AM" :chart-height="panelHeight" name="富时中国三倍做多" :k-days="20"
|
<k-line-chart code="usYINN.AM" :chart-height="panelHeight" name="富时中国三倍做多" :k-days="20"
|
||||||
:dark-theme="true"></k-line-chart>
|
:dark-theme="true"></k-line-chart>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
<n-tab-pane name="VIX恐慌指数" tab="VIX恐慌指数">
|
|
||||||
<k-line-chart code="usUVXY.AM" :chart-height="panelHeight" name="VIX恐慌指数" :k-days="20"
|
|
||||||
:dark-theme="true"></k-line-chart>
|
|
||||||
</n-tab-pane>
|
|
||||||
</n-tabs>
|
</n-tabs>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
<n-tab-pane name="行业排名" tab="行业排名">
|
|
||||||
<n-tabs type="card" animated>
|
|
||||||
<n-tab-pane name="行业涨幅排名" tab="行业涨幅排名">
|
|
||||||
<n-table striped>
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<n-th>行业名称</n-th>
|
|
||||||
<n-th @click="changeIndustryRankSort">行业涨幅
|
|
||||||
<n-icon v-if="sort==='0'" :component="CaretDown"/>
|
|
||||||
<n-icon v-if="sort==='1'" :component="CaretUp"/>
|
|
||||||
</n-th>
|
|
||||||
<n-th>行业5日涨幅</n-th>
|
|
||||||
<n-th>行业20日涨幅</n-th>
|
|
||||||
<n-th>领涨股</n-th>
|
|
||||||
<n-th>涨幅</n-th>
|
|
||||||
<n-th>最新价</n-th>
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="item in industryRanks" :key="item.bd_code">
|
|
||||||
<n-td>
|
|
||||||
<n-tag :bordered=false type="info">{{ item.bd_name }}</n-tag>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.bd_zdf>0?'error':'success'">{{ item.bd_zdf }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.bd_zdf5>0?'error':'success'">{{ item.bd_zdf5 }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.bd_zdf20>0?'error':'success'">{{ item.bd_zdf20 }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.nzg_zdf>0?'error':'success'"> {{ item.nzg_name }}
|
|
||||||
<n-text type="info">{{ item.nzg_code }}</n-text>
|
|
||||||
</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.nzg_zdf>0?'error':'success'"> {{ item.nzg_zdf }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.nzg_zdf>0?'error':'success'">{{ item.nzg_zxj }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
<n-table striped>
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<n-th>行业名称</n-th>
|
|
||||||
<n-th @click="changeIndustryRankSort">行业涨幅
|
|
||||||
<n-icon v-if="sort==='0'" :component="CaretDown"/>
|
|
||||||
<n-icon v-if="sort==='1'" :component="CaretUp"/>
|
|
||||||
</n-th>
|
|
||||||
<n-th>行业5日涨幅</n-th>
|
|
||||||
<n-th>行业20日涨幅</n-th>
|
|
||||||
<n-th>领涨股</n-th>
|
|
||||||
<n-th>涨幅</n-th>
|
|
||||||
<n-th>最新价</n-th>
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="item in industryRanks" :key="item.bd_code">
|
|
||||||
<n-td>
|
|
||||||
<n-tag :bordered=false type="info">{{ item.bd_name }}</n-tag>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.bd_zdf>0?'error':'success'">{{ item.bd_zdf }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.bd_zdf5>0?'error':'success'">{{ item.bd_zdf5 }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.bd_zdf20>0?'error':'success'">{{ item.bd_zdf20 }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.nzg_zdf>0?'error':'success'"> {{ item.nzg_name }}
|
|
||||||
<n-text type="info">{{ item.nzg_code }}</n-text>
|
|
||||||
</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.nzg_zdf>0?'error':'success'"> {{ item.nzg_zdf }}%</n-text>
|
|
||||||
</n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-text :type="item.nzg_zdf>0?'error':'success'">{{ item.nzg_zxj }}</n-text>
|
|
||||||
</n-td>
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="行业资金排名(净流入)" tab="行业资金排名">
|
|
||||||
<industryMoneyRank :fenlei="'0'" :header-title="'行业资金排名(净流入)'" :sort="'netamount'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="证监会行业资金排名(净流入)" tab="证监会行业资金排名">
|
|
||||||
<industryMoneyRank :fenlei="'2'" :header-title="'证监会行业资金排名(净流入)'" :sort="'netamount'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="概念板块资金排名(净流入)" tab="概念板块资金排名">
|
|
||||||
<industryMoneyRank :fenlei="'1'" :header-title="'概念板块资金排名(净流入)'" :sort="'netamount'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
</n-tabs>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="个股资金流向" tab="个股资金流向">
|
|
||||||
<n-tabs type="card" animated>
|
|
||||||
<n-tab-pane name="netamount" tab="净流入额排名">
|
|
||||||
<RankTable :header-title="'净流入额排名'" :sort="'netamount'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="outamount" tab="流出资金排名">
|
|
||||||
<RankTable :header-title="'流出资金排名'" :sort="'outamount'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="ratioamount" tab="净流入率排名">
|
|
||||||
<RankTable :header-title="'净流入率排名'" :sort="'ratioamount'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="r0_net" tab="主力净流入额排名">
|
|
||||||
<RankTable :header-title="'主力净流入额排名'" :sort="'r0_net'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="r0_out" tab="主力流出排名">
|
|
||||||
<RankTable :header-title="'主力流出排名'" :sort="'r0_out'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="r0_ratio" tab="主力净流入率排名">
|
|
||||||
<RankTable :header-title="'主力净流入率排名'" :sort="'r0_ratio'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="r3_net" tab="散户净流入额排名">
|
|
||||||
<RankTable :header-title="'散户净流入额排名'" :sort="'r3_net'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="r3_out" tab="散户流出排名">
|
|
||||||
<RankTable :header-title="'散户流出排名'" :sort="'r3_out'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="r3_ratio" tab="散户净流入率排名">
|
|
||||||
<RankTable :header-title="'散户净流入率排名'" :sort="'r3_ratio'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
</n-tabs>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="龙虎榜" tab="龙虎榜">
|
|
||||||
<LongTigerRankList />
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="个股研报" tab="个股研报">
|
|
||||||
<StockResearchReportList :stock-code="stockCode"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="公司公告" tab="公司公告 ">
|
|
||||||
<StockNoticeList :stock-code="stockCode" />
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="行业研究" tab="行业研究 ">
|
|
||||||
<IndustryResearchReportList/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="当前热门" tab="当前热门">
|
|
||||||
<n-tabs type="card" animated>
|
|
||||||
<n-tab-pane name="全球" tab="全球">
|
|
||||||
<HotStockList :market-type="'10'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="沪深" tab="沪深">
|
|
||||||
<HotStockList :market-type="'12'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="港股" tab="港股">
|
|
||||||
<HotStockList :market-type="'13'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="美股" tab="美股">
|
|
||||||
<HotStockList :market-type="'11'"/>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="热门话题" tab="热门话题">
|
|
||||||
<n-grid :cols="1" :y-gap="10">
|
|
||||||
<n-grid-item>
|
|
||||||
<HotTopics/>
|
|
||||||
</n-grid-item>
|
|
||||||
<!-- <n-grid-item>-->
|
|
||||||
<!-- <HotEvents/>-->
|
|
||||||
<!-- </n-grid-item>-->
|
|
||||||
</n-grid>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="重大事件时间轴" tab="重大事件时间轴">
|
|
||||||
<InvestCalendarTimeLine />
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="财经日历" tab="财经日历">
|
|
||||||
<ClsCalendarTimeLine />
|
|
||||||
</n-tab-pane>
|
|
||||||
</n-tabs>
|
|
||||||
</n-tab-pane>
|
|
||||||
<n-tab-pane name="指标选股" tab="指标选股">
|
|
||||||
<select-stock />
|
|
||||||
</n-tab-pane>
|
|
||||||
</n-tabs>
|
</n-tabs>
|
||||||
</n-card>
|
</n-card>
|
||||||
<n-modal transform-origin="center" v-model:show="summaryModal" preset="card" style="width: 800px;"
|
<n-modal transform-origin="center" v-model:show="summaryModal" preset="card" style="width: 800px;" :title="'AI市场资讯总结'" >
|
||||||
:title="'AI市场资讯总结'">
|
|
||||||
<n-spin size="small" :show="loading">
|
<n-spin size="small" :show="loading">
|
||||||
<MdPreview style="height: 440px;text-align: left" :modelValue="aiSummary" :theme="theme"/>
|
<MdPreview style="height: 440px;text-align: left" :modelValue="aiSummary" :theme="theme"/>
|
||||||
</n-spin>
|
</n-spin>
|
||||||
@ -616,10 +345,8 @@ function ReFlesh(source) {
|
|||||||
</template>
|
</template>
|
||||||
<template #action>
|
<template #action>
|
||||||
<n-flex justify="space-between" style="margin-bottom: 10px">
|
<n-flex justify="space-between" style="margin-bottom: 10px">
|
||||||
<n-select style="width: 49%" v-model:value="sysPromptId" label-field="name" value-field="ID"
|
<n-select style="width: 49%" v-model:value="sysPromptId" label-field="name" value-field="ID" :options="sysPromptOptions" placeholder="请选择系统提示词" />
|
||||||
:options="sysPromptOptions" placeholder="请选择系统提示词"/>
|
<n-select style="width: 49%" v-model:value="question" label-field="name" value-field="content" :options="userPromptOptions" placeholder="请选择用户提示词" />
|
||||||
<n-select style="width: 49%" v-model:value="question" label-field="name" value-field="content"
|
|
||||||
:options="userPromptOptions" placeholder="请选择用户提示词"/>
|
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<n-flex justify="right">
|
<n-flex justify="right">
|
||||||
<n-input v-model:value="question" style="text-align: left" clearable
|
<n-input v-model:value="question" style="text-align: left" clearable
|
||||||
@ -647,8 +374,6 @@ function ReFlesh(source) {
|
|||||||
</n-input-group>
|
</n-input-group>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
|
@ -1,374 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {onMounted, ref} from "vue";
|
|
||||||
import {GetStockMoneyTrendByDay} from "../../wailsjs/go/main/App";
|
|
||||||
import * as echarts from "echarts";
|
|
||||||
|
|
||||||
const {code, name, darkTheme, days, chartHeight} = defineProps({
|
|
||||||
code: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
days: {
|
|
||||||
type: Number,
|
|
||||||
default: 14
|
|
||||||
},
|
|
||||||
chartHeight: {
|
|
||||||
type: Number,
|
|
||||||
default: 500
|
|
||||||
},
|
|
||||||
darkTheme: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const LineChartRef = ref(null);
|
|
||||||
|
|
||||||
onMounted(
|
|
||||||
() => {
|
|
||||||
handleLine(code, days)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const handleLine = (code, days) => {
|
|
||||||
GetStockMoneyTrendByDay(code, days).then(result => {
|
|
||||||
//console.log("GetStockMoneyTrendByDay", result)
|
|
||||||
const chart = echarts.init(LineChartRef.value);
|
|
||||||
const categoryData = [];
|
|
||||||
const netamount_values = [];
|
|
||||||
const r0_net_values = [];
|
|
||||||
const trades_values = [];
|
|
||||||
let volume = []
|
|
||||||
|
|
||||||
let min = 0
|
|
||||||
let max = 0
|
|
||||||
for (let i = 0; i < result.length; i++) {
|
|
||||||
let resultElement = result[i]
|
|
||||||
categoryData.push(resultElement.opendate)
|
|
||||||
let netamount = (resultElement.netamount / 10000).toFixed(2);
|
|
||||||
netamount_values.push(netamount)
|
|
||||||
let price = Number(resultElement.trade);
|
|
||||||
trades_values.push(price)
|
|
||||||
r0_net_values.push((resultElement.r0_net / 10000).toFixed(2))
|
|
||||||
|
|
||||||
if (min === 0 || min > price) {
|
|
||||||
min = price
|
|
||||||
}
|
|
||||||
if (max < price) {
|
|
||||||
max = price
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
let b = Number(Number(result[i].netamount) + Number(result[i - 1].netamount)) / 10000
|
|
||||||
volume.push(b.toFixed(2))
|
|
||||||
} else {
|
|
||||||
volume.push((Number(result[i].netamount) / 10000).toFixed(2))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
//console.log("volume", volume)
|
|
||||||
const upColor = '#ec0000';
|
|
||||||
const downColor = '#00da3c';
|
|
||||||
let option = {
|
|
||||||
title: {
|
|
||||||
text: name,
|
|
||||||
left: '20px',
|
|
||||||
textStyle: {
|
|
||||||
color: darkTheme?'#ccc':'#456'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'axis',
|
|
||||||
axisPointer: {
|
|
||||||
type: 'cross',
|
|
||||||
lineStyle: {
|
|
||||||
color: '#376df4',
|
|
||||||
width: 1,
|
|
||||||
opacity: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: darkTheme?'#456':'#ccc',
|
|
||||||
backgroundColor: darkTheme?'#456':'#fff',
|
|
||||||
padding: 10,
|
|
||||||
textStyle: {
|
|
||||||
color: darkTheme?'#ccc':'#456'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
axisPointer: {
|
|
||||||
link: [
|
|
||||||
{
|
|
||||||
xAxisIndex: 'all'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
label: {
|
|
||||||
backgroundColor: '#888'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
show: true,
|
|
||||||
data: ['当日净流入', '主力当日净流入','累计净流入', '股价'],
|
|
||||||
selected: {
|
|
||||||
'当日净流入': true,
|
|
||||||
'主力当日净流入': true,
|
|
||||||
'累计净流入': true,
|
|
||||||
'股价': true,
|
|
||||||
},
|
|
||||||
//orient: 'vertical',
|
|
||||||
textStyle: {
|
|
||||||
color: darkTheme ? 'rgb(253,252,252)' : '#456'
|
|
||||||
},
|
|
||||||
right: 150,
|
|
||||||
},
|
|
||||||
dataZoom: [
|
|
||||||
{
|
|
||||||
type: 'inside',
|
|
||||||
xAxisIndex: [0, 1],
|
|
||||||
start: 86,
|
|
||||||
end: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
show: true,
|
|
||||||
xAxisIndex: [0, 1],
|
|
||||||
type: 'slider',
|
|
||||||
top: '90%',
|
|
||||||
start: 86,
|
|
||||||
end: 100
|
|
||||||
}
|
|
||||||
],
|
|
||||||
grid: [
|
|
||||||
{
|
|
||||||
left: '8%',
|
|
||||||
right: '8%',
|
|
||||||
height: '50%',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
left: '8%',
|
|
||||||
right: '8%',
|
|
||||||
top: '74%',
|
|
||||||
height: '15%'
|
|
||||||
},
|
|
||||||
],
|
|
||||||
xAxis: [
|
|
||||||
{
|
|
||||||
type: 'category',
|
|
||||||
data: categoryData,
|
|
||||||
axisPointer: {
|
|
||||||
z: 100
|
|
||||||
},
|
|
||||||
|
|
||||||
boundaryGap: false,
|
|
||||||
axisLine: { onZero: false },
|
|
||||||
splitLine: { show: false },
|
|
||||||
min: 'dataMin',
|
|
||||||
max: 'dataMax',
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
gridIndex: 1,
|
|
||||||
type: 'category',
|
|
||||||
data: categoryData,
|
|
||||||
axisLabel: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
yAxis: [
|
|
||||||
{
|
|
||||||
name: '当日净流入/万',
|
|
||||||
type: 'value',
|
|
||||||
axisLine: {
|
|
||||||
show: true
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '股价',
|
|
||||||
type: 'value',
|
|
||||||
min: min - 1,
|
|
||||||
max: max + 1,
|
|
||||||
minInterval: 0.01,
|
|
||||||
axisLine: {
|
|
||||||
show: true
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
gridIndex: 1,
|
|
||||||
name: '累计净流入/万',
|
|
||||||
type: 'value',
|
|
||||||
axisLine: {
|
|
||||||
show: true
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
yAxisIndex: 0,
|
|
||||||
name: '当日净流入',
|
|
||||||
data: netamount_values,
|
|
||||||
smooth: false,
|
|
||||||
showSymbol: false,
|
|
||||||
lineStyle: {
|
|
||||||
width: 2
|
|
||||||
},
|
|
||||||
markPoint: {
|
|
||||||
symbol: 'arrow',
|
|
||||||
symbolRotate: 90,
|
|
||||||
symbolSize: [10, 20],
|
|
||||||
symbolOffset: [10, 0],
|
|
||||||
itemStyle: {
|
|
||||||
color: '#0d7dfc'
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
position: 'right',
|
|
||||||
},
|
|
||||||
data: [
|
|
||||||
{type: 'max', name: 'Max'},
|
|
||||||
{type: 'min', name: 'Min'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
markLine: {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
type: 'average',
|
|
||||||
name: 'Average',
|
|
||||||
lineStyle: {
|
|
||||||
color: '#0077ff',
|
|
||||||
width: 0.5
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
type: 'line'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
yAxisIndex: 0,
|
|
||||||
name: '主力当日净流入',
|
|
||||||
data: r0_net_values,
|
|
||||||
smooth: false,
|
|
||||||
showSymbol: false,
|
|
||||||
lineStyle: {
|
|
||||||
width: 2
|
|
||||||
},
|
|
||||||
// markPoint: {
|
|
||||||
// symbol: 'arrow',
|
|
||||||
// symbolRotate: 90,
|
|
||||||
// symbolSize: [10, 20],
|
|
||||||
// symbolOffset: [10, 0],
|
|
||||||
// itemStyle: {
|
|
||||||
// color: '#0d7dfc'
|
|
||||||
// },
|
|
||||||
// label: {
|
|
||||||
// position: 'right',
|
|
||||||
// },
|
|
||||||
// data: [
|
|
||||||
// {type: 'max', name: 'Max'},
|
|
||||||
// {type: 'min', name: 'Min'}
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// markLine: {
|
|
||||||
// data: [
|
|
||||||
// {
|
|
||||||
// type: 'average',
|
|
||||||
// name: 'Average',
|
|
||||||
// lineStyle: {
|
|
||||||
// color: '#0077ff',
|
|
||||||
// width: 0.5
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
type: 'bar'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
yAxisIndex: 1,
|
|
||||||
name: '股价',
|
|
||||||
type: 'line',
|
|
||||||
data: trades_values,
|
|
||||||
smooth: true,
|
|
||||||
showSymbol: false,
|
|
||||||
lineStyle: {
|
|
||||||
width: 3
|
|
||||||
},
|
|
||||||
markPoint: {
|
|
||||||
symbol: 'arrow',
|
|
||||||
symbolRotate: 90,
|
|
||||||
symbolSize: [10, 20],
|
|
||||||
symbolOffset: [10, 0],
|
|
||||||
itemStyle: {
|
|
||||||
color: '#f39509'
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
position: 'right',
|
|
||||||
},
|
|
||||||
data: [
|
|
||||||
{type: 'max', name: 'Max'},
|
|
||||||
{type: 'min', name: 'Min'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
markLine: {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
type: 'average',
|
|
||||||
name: 'Average',
|
|
||||||
lineStyle: {
|
|
||||||
color: '#f39509',
|
|
||||||
width: 0.5
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'bar',
|
|
||||||
xAxisIndex: 1,
|
|
||||||
yAxisIndex: 2,
|
|
||||||
name: '累计净流入',
|
|
||||||
data: volume,
|
|
||||||
smooth: true,
|
|
||||||
showSymbol: false,
|
|
||||||
lineStyle: {
|
|
||||||
width: 2
|
|
||||||
},
|
|
||||||
markPoint: {
|
|
||||||
symbol: 'arrow',
|
|
||||||
symbolRotate: 90,
|
|
||||||
symbolSize: [10, 20],
|
|
||||||
symbolOffset: [10, 0],
|
|
||||||
// itemStyle: {
|
|
||||||
// color: '#f39509'
|
|
||||||
// },
|
|
||||||
label: {
|
|
||||||
position: 'right',
|
|
||||||
},
|
|
||||||
data: [
|
|
||||||
{type: 'max', name: 'Max'},
|
|
||||||
{type: 'min', name: 'Min'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
};
|
|
||||||
chart.setOption(option);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div ref="LineChartRef" style="width: 100%;height: auto;" :style="{height:chartHeight+'px'}"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,7 +1,4 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {ReFleshTelegraphList} from "../../wailsjs/go/main/App";
|
|
||||||
import {RefreshCircle, RefreshCircleSharp, RefreshOutline} from "@vicons/ionicons5";
|
|
||||||
|
|
||||||
const { headerTitle,newsList } = defineProps({
|
const { headerTitle,newsList } = defineProps({
|
||||||
headerTitle: {
|
headerTitle: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -10,23 +7,14 @@ const { headerTitle,newsList } = defineProps({
|
|||||||
newsList: {
|
newsList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const emits = defineEmits(['update:message'])
|
|
||||||
|
|
||||||
const updateMessage = () => {
|
|
||||||
emits('update:message', headerTitle)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-list bordered>
|
<n-list bordered>
|
||||||
<template #header>
|
<template #header>
|
||||||
<n-flex justify="space-between">
|
{{ headerTitle }}
|
||||||
<n-tag :bordered="false" size="large" type="success" >{{ headerTitle }}</n-tag>
|
|
||||||
<n-button :bordered="false" @click="updateMessage"><n-icon color="#409EFF" size="25" :component="RefreshCircleSharp"/></n-button>
|
|
||||||
</n-flex>
|
|
||||||
</template>
|
</template>
|
||||||
<n-list-item v-for="item in newsList">
|
<n-list-item v-for="item in newsList">
|
||||||
<n-space justify="start">
|
<n-space justify="start">
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
|
|
||||||
import {CaretDown, CaretUp, RefreshCircleOutline} from "@vicons/ionicons5";
|
|
||||||
import {NText,useMessage} from "naive-ui";
|
|
||||||
import {onBeforeUnmount, onMounted, onUnmounted, ref} from "vue";
|
|
||||||
import {GetMoneyRankSina} from "../../wailsjs/go/main/App";
|
|
||||||
import KLineChart from "./KLineChart.vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
headerTitle: {
|
|
||||||
type: String,
|
|
||||||
default: '净流入额排名'
|
|
||||||
},
|
|
||||||
sort: {
|
|
||||||
type: String,
|
|
||||||
default: 'netamount'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const message = useMessage()
|
|
||||||
const dataList= ref([])
|
|
||||||
const sort = ref(props.sort)
|
|
||||||
const interval = ref(null)
|
|
||||||
onMounted(()=>{
|
|
||||||
sort.value=props.sort
|
|
||||||
GetMoneyRankSinaData()
|
|
||||||
interval.value=setInterval(()=>{
|
|
||||||
GetMoneyRankSinaData()
|
|
||||||
},1000*60)
|
|
||||||
})
|
|
||||||
onBeforeUnmount(()=>{
|
|
||||||
clearInterval(interval.value)
|
|
||||||
})
|
|
||||||
function GetMoneyRankSinaData(){
|
|
||||||
message.loading("正在刷新数据...")
|
|
||||||
GetMoneyRankSina(sort.value).then(result => {
|
|
||||||
if(result.length>0){
|
|
||||||
dataList.value = result
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-table striped size="small">
|
|
||||||
<n-thead>
|
|
||||||
<n-tr>
|
|
||||||
<n-th>代码</n-th>
|
|
||||||
<n-th>名称</n-th>
|
|
||||||
<n-th>最新价</n-th>
|
|
||||||
<n-th>涨跌幅</n-th>
|
|
||||||
<n-th>换手率</n-th>
|
|
||||||
<n-th>成交额/万</n-th>
|
|
||||||
<n-th>流出资金/万</n-th>
|
|
||||||
<n-th>流入资金/万</n-th>
|
|
||||||
<n-th>净流入/万</n-th>
|
|
||||||
<n-th>净流入率</n-th>
|
|
||||||
<n-th v-if="sort === 'r0_net'||sort==='r0_out'">主力流出/万</n-th>
|
|
||||||
<n-th v-if="sort === 'r0_net'">主力流入/万</n-th>
|
|
||||||
<n-th v-if="sort === 'r0_net'">主力净流入/万</n-th>
|
|
||||||
<n-th >主力净流入率</n-th>
|
|
||||||
<n-th v-if="sort === 'r3_net'||sort==='r3_out'">散户流出/万</n-th>
|
|
||||||
<n-th v-if="sort === 'r3_net'">散户流入/万</n-th>
|
|
||||||
<n-th v-if="sort === 'r3_net'">散户净流入/万</n-th>
|
|
||||||
<n-th >散户净流入率</n-th>
|
|
||||||
</n-tr>
|
|
||||||
</n-thead>
|
|
||||||
<n-tbody>
|
|
||||||
<n-tr v-for="item in dataList" :key="item.symbol">
|
|
||||||
<n-td><n-tag :bordered=false type="info">{{ item.symbol }}</n-tag></n-td>
|
|
||||||
<n-td>
|
|
||||||
<n-popover trigger="hover" placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<n-button tag="a" text :type="item.changeratio>0?'error':'success'" :bordered=false >{{ item.name }}</n-button>
|
|
||||||
</template>
|
|
||||||
<k-line-chart style="width: 800px" :code="item.symbol" :chart-height="500" :name="item.name" :k-days="20" :dark-theme="true"></k-line-chart>
|
|
||||||
</n-popover>
|
|
||||||
</n-td>
|
|
||||||
<n-td><n-text :type="item.changeratio>0?'error':'success'">{{item.trade}}</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.changeratio>0?'error':'success'">{{(item.changeratio*100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.turnover>500?'error':'info'">{{(item.turnover/100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
<n-td><n-text type="info">{{(item.amount/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td><n-text type="info"> {{(item.outamount/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td><n-text type="info"> {{(item.inamount/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td><n-text type="info"> {{(item.netamount/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td><n-text :type="item.ratioamount>0?'error':'success'"> {{(item.ratioamount*100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
<n-td v-if="sort === 'r0_net'||sort==='r0_out'"><n-text type="success"> {{(item.r0_out/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td v-if="sort === 'r0_net'"><n-text type="error"> {{(item.r0_in/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td v-if="sort === 'r0_net'"><n-text :type="item.r0_net>0?'error':'success'"> {{(item.r0_net/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td ><n-text :type="item.r0_ratio>0?'error':'success'"> {{(item.r0_ratio*100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
<n-td v-if="sort === 'r3_net'||sort==='r3_out'"><n-text type="success"> {{(item.r3_out/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td v-if="sort === 'r3_net'"><n-text type="error"> {{(item.r3_in/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td v-if="sort === 'r3_net'"><n-text :type="item.r3_net>0?'error':'success'"> {{(item.r3_net/10000).toFixed(2)}}</n-text></n-td>
|
|
||||||
<n-td ><n-text :type="item.r3_ratio>0?'error':'success'"> {{(item.r3_ratio*100).toFixed(2)}}%</n-text></n-td>
|
|
||||||
</n-tr>
|
|
||||||
</n-tbody>
|
|
||||||
</n-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -45,7 +45,6 @@ const formValue = ref({
|
|||||||
enableNews:false,
|
enableNews:false,
|
||||||
darkTheme:true,
|
darkTheme:true,
|
||||||
enableFund:false,
|
enableFund:false,
|
||||||
enablePushNews:false,
|
|
||||||
})
|
})
|
||||||
const promptTemplates=ref([])
|
const promptTemplates=ref([])
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
@ -79,14 +78,13 @@ onMounted(()=>{
|
|||||||
formValue.value.enableNews = res.enableNews
|
formValue.value.enableNews = res.enableNews
|
||||||
formValue.value.darkTheme = res.darkTheme
|
formValue.value.darkTheme = res.darkTheme
|
||||||
formValue.value.enableFund = res.enableFund
|
formValue.value.enableFund = res.enableFund
|
||||||
formValue.value.enablePushNews = res.enablePushNews
|
|
||||||
|
|
||||||
//console.log(res)
|
console.log(res)
|
||||||
})
|
})
|
||||||
//message.info("加载完成")
|
//message.info("加载完成")
|
||||||
|
|
||||||
GetPromptTemplates("","").then(res=>{
|
GetPromptTemplates("","").then(res=>{
|
||||||
//console.log(res)
|
console.log(res)
|
||||||
promptTemplates.value=res
|
promptTemplates.value=res
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -120,7 +118,6 @@ function saveConfig(){
|
|||||||
enableNews:formValue.value.enableNews,
|
enableNews:formValue.value.enableNews,
|
||||||
darkTheme:formValue.value.darkTheme,
|
darkTheme:formValue.value.darkTheme,
|
||||||
enableFund:formValue.value.enableFund,
|
enableFund:formValue.value.enableFund,
|
||||||
enablePushNews:formValue.value.enablePushNews
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -168,7 +165,7 @@ function importConfig(){
|
|||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
let config = JSON.parse(e.target.result);
|
let config = JSON.parse(e.target.result);
|
||||||
//console.log(config)
|
console.log(config)
|
||||||
formValue.value.ID = config.ID
|
formValue.value.ID = config.ID
|
||||||
formValue.value.tushareToken = config.tushareToken
|
formValue.value.tushareToken = config.tushareToken
|
||||||
formValue.value.dingPush = {
|
formValue.value.dingPush = {
|
||||||
@ -198,7 +195,6 @@ function importConfig(){
|
|||||||
formValue.value.enableNews = config.enableNews
|
formValue.value.enableNews = config.enableNews
|
||||||
formValue.value.darkTheme = config.darkTheme
|
formValue.value.darkTheme = config.darkTheme
|
||||||
formValue.value.enableFund = config.enableFund
|
formValue.value.enableFund = config.enableFund
|
||||||
formValue.value.enablePushNews = config.enablePushNews
|
|
||||||
// formRef.value.resetFields()
|
// formRef.value.resetFields()
|
||||||
};
|
};
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
@ -208,7 +204,7 @@ function importConfig(){
|
|||||||
|
|
||||||
|
|
||||||
window.onerror = function (event, source, lineno, colno, error) {
|
window.onerror = function (event, source, lineno, colno, error) {
|
||||||
//console.log(event, source, lineno, colno, error)
|
console.log(event, source, lineno, colno, error)
|
||||||
// 将错误信息发送给后端
|
// 将错误信息发送给后端
|
||||||
EventsEmit("frontendError", {
|
EventsEmit("frontendError", {
|
||||||
page: "settings.vue",
|
page: "settings.vue",
|
||||||
@ -241,14 +237,14 @@ function savePrompt(){
|
|||||||
AddPrompt(formPrompt.value).then(res=>{
|
AddPrompt(formPrompt.value).then(res=>{
|
||||||
message.success(res)
|
message.success(res)
|
||||||
GetPromptTemplates("","").then(res=>{
|
GetPromptTemplates("","").then(res=>{
|
||||||
//console.log(res)
|
console.log(res)
|
||||||
promptTemplates.value=res
|
promptTemplates.value=res
|
||||||
})
|
})
|
||||||
showManagePromptsModal.value=false
|
showManagePromptsModal.value=false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function editPrompt(prompt){
|
function editPrompt(prompt){
|
||||||
//console.log(prompt)
|
console.log(prompt)
|
||||||
formPrompt.value.ID=prompt.ID
|
formPrompt.value.ID=prompt.ID
|
||||||
formPrompt.value.Name=prompt.name
|
formPrompt.value.Name=prompt.name
|
||||||
formPrompt.value.Content=prompt.content
|
formPrompt.value.Content=prompt.content
|
||||||
@ -259,7 +255,7 @@ function deletePrompt(ID){
|
|||||||
DelPrompt(ID).then(res=>{
|
DelPrompt(ID).then(res=>{
|
||||||
message.success(res)
|
message.success(res)
|
||||||
GetPromptTemplates("","").then(res=>{
|
GetPromptTemplates("","").then(res=>{
|
||||||
//console.log(res)
|
console.log(res)
|
||||||
promptTemplates.value=res
|
promptTemplates.value=res
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -292,7 +288,7 @@ function deletePrompt(ID){
|
|||||||
<n-form-item-gi :span="10" label="浏览器安装路径:" path="browserPath" >
|
<n-form-item-gi :span="10" label="浏览器安装路径:" path="browserPath" >
|
||||||
<n-input type="text" placeholder="浏览器安装路径" v-model:value="formValue.browserPath" clearable />
|
<n-input type="text" placeholder="浏览器安装路径" v-model:value="formValue.browserPath" clearable />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="6" label="指数基金:" path="enableFund" >
|
<n-form-item-gi :span="6" label="是否启用指数基金:" path="enableFund" >
|
||||||
<n-switch v-model:value="formValue.enableFund" />
|
<n-switch v-model:value="formValue.enableFund" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
</n-grid>
|
</n-grid>
|
||||||
@ -301,21 +297,18 @@ function deletePrompt(ID){
|
|||||||
<n-gi :span="24">
|
<n-gi :span="24">
|
||||||
<n-text type="success" style="font-size: 25px;font-weight: bold">通知设置</n-text>
|
<n-text type="success" style="font-size: 25px;font-weight: bold">通知设置</n-text>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-form-item-gi :span="4" label="钉钉推送:" path="dingPush.enable" >
|
<n-form-item-gi :span="6" label="是否启用钉钉推送:" path="dingPush.enable" >
|
||||||
<n-switch v-model:value="formValue.dingPush.enable" />
|
<n-switch v-model:value="formValue.dingPush.enable" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="4" label="本地推送:" path="localPush.enable" >
|
<n-form-item-gi :span="6" label="是否启用本地推送:" path="localPush.enable" >
|
||||||
<n-switch v-model:value="formValue.localPush.enable" />
|
<n-switch v-model:value="formValue.localPush.enable" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="4" label="弹幕功能:" path="enableDanmu" >
|
<n-form-item-gi :span="5" label="弹幕功能:" path="enableDanmu" >
|
||||||
<n-switch v-model:value="formValue.enableDanmu" />
|
<n-switch v-model:value="formValue.enableDanmu" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="4" label="显示滚动快讯:" path="enableNews" >
|
<n-form-item-gi :span="5" label="是否显示滚动快讯(重启生效):" path="enableNews" >
|
||||||
<n-switch v-model:value="formValue.enableNews" />
|
<n-switch v-model:value="formValue.enableNews" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="4" label="市场资讯提醒:" path="enablePushNews" >
|
|
||||||
<n-switch v-model:value="formValue.enablePushNews" />
|
|
||||||
</n-form-item-gi>
|
|
||||||
<n-form-item-gi :span="22" v-if="formValue.dingPush.enable" label="钉钉机器人接口地址:" path="dingPush.dingRobot" >
|
<n-form-item-gi :span="22" v-if="formValue.dingPush.enable" label="钉钉机器人接口地址:" path="dingPush.dingRobot" >
|
||||||
<n-input placeholder="请输入钉钉机器人接口地址" v-model:value="formValue.dingPush.dingRobot"/>
|
<n-input placeholder="请输入钉钉机器人接口地址" v-model:value="formValue.dingPush.dingRobot"/>
|
||||||
<n-button type="primary" @click="sendTestNotice">发送测试通知</n-button>
|
<n-button type="primary" @click="sendTestNotice">发送测试通知</n-button>
|
||||||
@ -326,7 +319,7 @@ function deletePrompt(ID){
|
|||||||
<n-gi :span="24">
|
<n-gi :span="24">
|
||||||
<n-text type="success" style="font-size: 25px;font-weight: bold">OpenAI设置</n-text>
|
<n-text type="success" style="font-size: 25px;font-weight: bold">OpenAI设置</n-text>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-form-item-gi :span="3" label="AI诊股:" path="openAI.enable" >
|
<n-form-item-gi :span="3" label="是否启用AI诊股:" path="openAI.enable" >
|
||||||
<n-switch v-model:value="formValue.openAI.enable" />
|
<n-switch v-model:value="formValue.openAI.enable" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="9" v-if="formValue.openAI.enable" label="openAI 接口地址:" path="openAI.baseUrl" >
|
<n-form-item-gi :span="9" v-if="formValue.openAI.enable" label="openAI 接口地址:" path="openAI.baseUrl" >
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
import {createMemoryHistory, createRouter, createWebHashHistory, createWebHistory} from 'vue-router'
|
import {createMemoryHistory, createRouter, createWebHashHistory} from 'vue-router'
|
||||||
|
|
||||||
import stockView from '../components/stock.vue'
|
import stockView from '../components/stock.vue'
|
||||||
import settingsView from '../components/settings.vue'
|
import settingsView from '../components/settings.vue'
|
||||||
@ -12,11 +12,10 @@ const routes = [
|
|||||||
{ path: '/settings', component: settingsView,name: 'settings' },
|
{ path: '/settings', component: settingsView,name: 'settings' },
|
||||||
{ path: '/about', component: about,name: 'about' },
|
{ path: '/about', component: about,name: 'about' },
|
||||||
{ path: '/market', component: market,name: 'market' },
|
{ path: '/market', component: market,name: 'market' },
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHashHistory(),
|
||||||
routes,
|
routes,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
38
frontend/wailsjs/go/main/App.d.ts
vendored
38
frontend/wailsjs/go/main/App.d.ts
vendored
@ -11,16 +11,10 @@ export function AddPrompt(arg1:models.Prompt):Promise<string>;
|
|||||||
|
|
||||||
export function AddStockGroup(arg1:number,arg2:string):Promise<string>;
|
export function AddStockGroup(arg1:number,arg2:string):Promise<string>;
|
||||||
|
|
||||||
export function AnalyzeSentiment(arg1:string):Promise<data.SentimentResult>;
|
|
||||||
|
|
||||||
export function CheckUpdate():Promise<void>;
|
export function CheckUpdate():Promise<void>;
|
||||||
|
|
||||||
export function ClsCalendar():Promise<Array<any>>;
|
|
||||||
|
|
||||||
export function DelPrompt(arg1:number):Promise<string>;
|
export function DelPrompt(arg1:number):Promise<string>;
|
||||||
|
|
||||||
export function EMDictCode(arg1:string):Promise<Array<any>>;
|
|
||||||
|
|
||||||
export function ExportConfig():Promise<string>;
|
export function ExportConfig():Promise<string>;
|
||||||
|
|
||||||
export function Follow(arg1:string):Promise<string>;
|
export function Follow(arg1:string):Promise<string>;
|
||||||
@ -39,12 +33,6 @@ export function GetGroupList():Promise<Array<data.Group>>;
|
|||||||
|
|
||||||
export function GetGroupStockList(arg1:number):Promise<Array<data.GroupStock>>;
|
export function GetGroupStockList(arg1:number):Promise<Array<data.GroupStock>>;
|
||||||
|
|
||||||
export function GetIndustryMoneyRankSina(arg1:string,arg2:string):Promise<Array<Record<string, any>>>;
|
|
||||||
|
|
||||||
export function GetIndustryRank(arg1:string,arg2:number):Promise<Array<any>>;
|
|
||||||
|
|
||||||
export function GetMoneyRankSina(arg1:string):Promise<Array<Record<string, any>>>;
|
|
||||||
|
|
||||||
export function GetPromptTemplates(arg1:string,arg2:string):Promise<any>;
|
export function GetPromptTemplates(arg1:string,arg2:string):Promise<any>;
|
||||||
|
|
||||||
export function GetStockCommonKLine(arg1:string,arg2:string,arg3:number):Promise<any>;
|
export function GetStockCommonKLine(arg1:string,arg2:string,arg3:number):Promise<any>;
|
||||||
@ -53,10 +41,6 @@ export function GetStockKLine(arg1:string,arg2:string,arg3:number):Promise<any>;
|
|||||||
|
|
||||||
export function GetStockList(arg1:string):Promise<Array<data.StockBasic>>;
|
export function GetStockList(arg1:string):Promise<Array<data.StockBasic>>;
|
||||||
|
|
||||||
export function GetStockMinutePriceLineData(arg1:string,arg2:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function GetStockMoneyTrendByDay(arg1:string,arg2:number):Promise<Array<Record<string, any>>>;
|
|
||||||
|
|
||||||
export function GetTelegraphList(arg1:string):Promise<any>;
|
export function GetTelegraphList(arg1:string):Promise<any>;
|
||||||
|
|
||||||
export function GetVersionInfo():Promise<models.VersionInfo>;
|
export function GetVersionInfo():Promise<models.VersionInfo>;
|
||||||
@ -67,24 +51,8 @@ export function GlobalStockIndexes():Promise<Record<string, any>>;
|
|||||||
|
|
||||||
export function Greet(arg1:string):Promise<data.StockInfo>;
|
export function Greet(arg1:string):Promise<data.StockInfo>;
|
||||||
|
|
||||||
export function HotEvent(arg1:number):Promise<any>;
|
|
||||||
|
|
||||||
export function HotStock(arg1:string):Promise<any>;
|
|
||||||
|
|
||||||
export function HotTopic(arg1:number):Promise<Array<any>>;
|
|
||||||
|
|
||||||
export function IndustryResearchReport(arg1:string):Promise<Array<any>>;
|
|
||||||
|
|
||||||
export function InvestCalendarTimeLine(arg1:string):Promise<Array<any>>;
|
|
||||||
|
|
||||||
export function LongTigerRank(arg1:string):Promise<any>;
|
|
||||||
|
|
||||||
export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise<void>;
|
export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise<void>;
|
||||||
|
|
||||||
export function NewsPush(arg1:any):Promise<void>;
|
|
||||||
|
|
||||||
export function ReFleshTelegraphList(arg1:string):Promise<any>;
|
|
||||||
|
|
||||||
export function RemoveGroup(arg1:number):Promise<string>;
|
export function RemoveGroup(arg1:number):Promise<string>;
|
||||||
|
|
||||||
export function RemoveStockGroup(arg1:string,arg2:string,arg3:number):Promise<string>;
|
export function RemoveStockGroup(arg1:string,arg2:string,arg3:number):Promise<string>;
|
||||||
@ -93,8 +61,6 @@ export function SaveAIResponseResult(arg1:string,arg2:string,arg3:string,arg4:st
|
|||||||
|
|
||||||
export function SaveAsMarkdown(arg1:string,arg2:string):Promise<string>;
|
export function SaveAsMarkdown(arg1:string,arg2:string):Promise<string>;
|
||||||
|
|
||||||
export function SearchStock(arg1:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function SendDingDingMessage(arg1:string,arg2:string):Promise<string>;
|
export function SendDingDingMessage(arg1:string,arg2:string):Promise<string>;
|
||||||
|
|
||||||
export function SendDingDingMessageByType(arg1:string,arg2:string,arg3:number):Promise<string>;
|
export function SendDingDingMessageByType(arg1:string,arg2:string,arg3:number):Promise<string>;
|
||||||
@ -109,10 +75,6 @@ export function SetStockSort(arg1:number,arg2:string):Promise<void>;
|
|||||||
|
|
||||||
export function ShareAnalysis(arg1:string,arg2:string):Promise<string>;
|
export function ShareAnalysis(arg1:string,arg2:string):Promise<string>;
|
||||||
|
|
||||||
export function StockNotice(arg1:string):Promise<Array<any>>;
|
|
||||||
|
|
||||||
export function StockResearchReport(arg1:string):Promise<Array<any>>;
|
|
||||||
|
|
||||||
export function SummaryStockNews(arg1:string,arg2:any):Promise<void>;
|
export function SummaryStockNews(arg1:string,arg2:any):Promise<void>;
|
||||||
|
|
||||||
export function UnFollow(arg1:string):Promise<string>;
|
export function UnFollow(arg1:string):Promise<string>;
|
||||||
|
@ -18,26 +18,14 @@ export function AddStockGroup(arg1, arg2) {
|
|||||||
return window['go']['main']['App']['AddStockGroup'](arg1, arg2);
|
return window['go']['main']['App']['AddStockGroup'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AnalyzeSentiment(arg1) {
|
|
||||||
return window['go']['main']['App']['AnalyzeSentiment'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CheckUpdate() {
|
export function CheckUpdate() {
|
||||||
return window['go']['main']['App']['CheckUpdate']();
|
return window['go']['main']['App']['CheckUpdate']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ClsCalendar() {
|
|
||||||
return window['go']['main']['App']['ClsCalendar']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DelPrompt(arg1) {
|
export function DelPrompt(arg1) {
|
||||||
return window['go']['main']['App']['DelPrompt'](arg1);
|
return window['go']['main']['App']['DelPrompt'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EMDictCode(arg1) {
|
|
||||||
return window['go']['main']['App']['EMDictCode'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ExportConfig() {
|
export function ExportConfig() {
|
||||||
return window['go']['main']['App']['ExportConfig']();
|
return window['go']['main']['App']['ExportConfig']();
|
||||||
}
|
}
|
||||||
@ -74,18 +62,6 @@ export function GetGroupStockList(arg1) {
|
|||||||
return window['go']['main']['App']['GetGroupStockList'](arg1);
|
return window['go']['main']['App']['GetGroupStockList'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetIndustryMoneyRankSina(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['GetIndustryMoneyRankSina'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetIndustryRank(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['GetIndustryRank'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetMoneyRankSina(arg1) {
|
|
||||||
return window['go']['main']['App']['GetMoneyRankSina'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetPromptTemplates(arg1, arg2) {
|
export function GetPromptTemplates(arg1, arg2) {
|
||||||
return window['go']['main']['App']['GetPromptTemplates'](arg1, arg2);
|
return window['go']['main']['App']['GetPromptTemplates'](arg1, arg2);
|
||||||
}
|
}
|
||||||
@ -102,14 +78,6 @@ export function GetStockList(arg1) {
|
|||||||
return window['go']['main']['App']['GetStockList'](arg1);
|
return window['go']['main']['App']['GetStockList'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetStockMinutePriceLineData(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['GetStockMinutePriceLineData'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetStockMoneyTrendByDay(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['GetStockMoneyTrendByDay'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetTelegraphList(arg1) {
|
export function GetTelegraphList(arg1) {
|
||||||
return window['go']['main']['App']['GetTelegraphList'](arg1);
|
return window['go']['main']['App']['GetTelegraphList'](arg1);
|
||||||
}
|
}
|
||||||
@ -130,42 +98,10 @@ export function Greet(arg1) {
|
|||||||
return window['go']['main']['App']['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);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function NewChatStream(arg1, arg2, arg3, arg4) {
|
export function NewChatStream(arg1, arg2, arg3, arg4) {
|
||||||
return window['go']['main']['App']['NewChatStream'](arg1, arg2, arg3, arg4);
|
return window['go']['main']['App']['NewChatStream'](arg1, arg2, arg3, arg4);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NewsPush(arg1) {
|
|
||||||
return window['go']['main']['App']['NewsPush'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReFleshTelegraphList(arg1) {
|
|
||||||
return window['go']['main']['App']['ReFleshTelegraphList'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RemoveGroup(arg1) {
|
export function RemoveGroup(arg1) {
|
||||||
return window['go']['main']['App']['RemoveGroup'](arg1);
|
return window['go']['main']['App']['RemoveGroup'](arg1);
|
||||||
}
|
}
|
||||||
@ -182,10 +118,6 @@ export function SaveAsMarkdown(arg1, arg2) {
|
|||||||
return window['go']['main']['App']['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) {
|
export function SendDingDingMessage(arg1, arg2) {
|
||||||
return window['go']['main']['App']['SendDingDingMessage'](arg1, arg2);
|
return window['go']['main']['App']['SendDingDingMessage'](arg1, arg2);
|
||||||
}
|
}
|
||||||
@ -214,14 +146,6 @@ export function ShareAnalysis(arg1, arg2) {
|
|||||||
return window['go']['main']['App']['ShareAnalysis'](arg1, arg2);
|
return window['go']['main']['App']['ShareAnalysis'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StockNotice(arg1) {
|
|
||||||
return window['go']['main']['App']['StockNotice'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function StockResearchReport(arg1) {
|
|
||||||
return window['go']['main']['App']['StockResearchReport'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SummaryStockNews(arg1, arg2) {
|
export function SummaryStockNews(arg1, arg2) {
|
||||||
return window['go']['main']['App']['SummaryStockNews'](arg1, arg2);
|
return window['go']['main']['App']['SummaryStockNews'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
@ -290,26 +290,6 @@ export namespace data {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class SentimentResult {
|
|
||||||
Score: number;
|
|
||||||
Category: number;
|
|
||||||
PositiveCount: number;
|
|
||||||
NegativeCount: number;
|
|
||||||
Description: string;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new SentimentResult(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.Score = source["Score"];
|
|
||||||
this.Category = source["Category"];
|
|
||||||
this.PositiveCount = source["PositiveCount"];
|
|
||||||
this.NegativeCount = source["NegativeCount"];
|
|
||||||
this.Description = source["Description"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class Settings {
|
export class Settings {
|
||||||
ID: number;
|
ID: number;
|
||||||
// Go type: time
|
// Go type: time
|
||||||
@ -342,7 +322,6 @@ export namespace data {
|
|||||||
darkTheme: boolean;
|
darkTheme: boolean;
|
||||||
browserPoolSize: number;
|
browserPoolSize: number;
|
||||||
enableFund: boolean;
|
enableFund: boolean;
|
||||||
enablePushNews: boolean;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new Settings(source);
|
return new Settings(source);
|
||||||
@ -378,7 +357,6 @@ export namespace data {
|
|||||||
this.darkTheme = source["darkTheme"];
|
this.darkTheme = source["darkTheme"];
|
||||||
this.browserPoolSize = source["browserPoolSize"];
|
this.browserPoolSize = source["browserPoolSize"];
|
||||||
this.enableFund = source["enableFund"];
|
this.enableFund = source["enableFund"];
|
||||||
this.enablePushNews = source["enablePushNews"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
17
go.mod
17
go.mod
@ -1,6 +1,8 @@
|
|||||||
module go-stock
|
module go-stock
|
||||||
|
|
||||||
go 1.23.0
|
go 1.23
|
||||||
|
|
||||||
|
toolchain go1.23.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.10.1
|
github.com/PuerkitoBio/goquery v1.10.1
|
||||||
@ -9,18 +11,16 @@ require (
|
|||||||
github.com/duke-git/lancet/v2 v2.3.4
|
github.com/duke-git/lancet/v2 v2.3.4
|
||||||
github.com/energye/systray v1.0.2
|
github.com/energye/systray v1.0.2
|
||||||
github.com/glebarez/sqlite v1.11.0
|
github.com/glebarez/sqlite v1.11.0
|
||||||
github.com/go-ego/gse v0.80.3
|
|
||||||
github.com/go-resty/resty/v2 v2.16.2
|
github.com/go-resty/resty/v2 v2.16.2
|
||||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
|
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
|
||||||
github.com/robertkrimen/otto v0.5.1
|
github.com/robertkrimen/otto v0.5.1
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/samber/lo v1.49.1
|
github.com/samber/lo v1.49.1
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/tidwall/gjson v1.14.2
|
|
||||||
github.com/wailsapp/wails/v2 v2.10.1
|
github.com/wailsapp/wails/v2 v2.10.1
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/sys v0.31.0
|
golang.org/x/sys v0.30.0
|
||||||
golang.org/x/text v0.23.0
|
golang.org/x/text v0.22.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
gorm.io/plugin/dbresolver v1.5.3
|
gorm.io/plugin/dbresolver v1.5.3
|
||||||
@ -62,18 +62,15 @@ require (
|
|||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/tevino/abool v0.0.0-20220530134649-2bfc934cb23c // indirect
|
github.com/tevino/abool v0.0.0-20220530134649-2bfc934cb23c // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
|
||||||
github.com/tidwall/pretty v1.2.0 // indirect
|
|
||||||
github.com/tkrajina/go-reflector v0.5.8 // indirect
|
github.com/tkrajina/go-reflector v0.5.8 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/vcaesar/cedar v0.20.2 // indirect
|
|
||||||
github.com/wailsapp/go-webview2 v1.0.19 // indirect
|
github.com/wailsapp/go-webview2 v1.0.19 // indirect
|
||||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||||
go.uber.org/multierr v1.10.0 // indirect
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
golang.org/x/crypto v0.33.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||||
golang.org/x/net v0.38.0 // indirect
|
golang.org/x/net v0.35.0 // indirect
|
||||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
modernc.org/libc v1.22.5 // indirect
|
modernc.org/libc v1.22.5 // indirect
|
||||||
|
28
go.sum
28
go.sum
@ -26,8 +26,6 @@ github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9g
|
|||||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||||
github.com/go-ego/gse v0.80.3 h1:YNFkjMhlhQnUeuoFcUEd1ivh6SOB764rT8GDsEbDiEg=
|
|
||||||
github.com/go-ego/gse v0.80.3/go.mod h1:Gt3A9Ry1Eso2Kza4MRaiZ7f2DTAvActmETY46Lxg0gU=
|
|
||||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/go-resty/resty/v2 v2.16.2 h1:CpRqTjIzq/rweXUt9+GxzzQdlkqMdt8Lm/fuK/CAbAg=
|
github.com/go-resty/resty/v2 v2.16.2 h1:CpRqTjIzq/rweXUt9+GxzzQdlkqMdt8Lm/fuK/CAbAg=
|
||||||
@ -119,22 +117,12 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
|||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tevino/abool v0.0.0-20220530134649-2bfc934cb23c h1:coVla7zpsycc+kA9NXpcvv2E4I7+ii6L5hZO2S6C3kw=
|
github.com/tevino/abool v0.0.0-20220530134649-2bfc934cb23c h1:coVla7zpsycc+kA9NXpcvv2E4I7+ii6L5hZO2S6C3kw=
|
||||||
github.com/tevino/abool v0.0.0-20220530134649-2bfc934cb23c/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
|
github.com/tevino/abool v0.0.0-20220530134649-2bfc934cb23c/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
|
||||||
github.com/tidwall/gjson v1.14.2 h1:6BBkirS0rAHjumnjHF6qgy5d2YAJ1TLIaFE2lzfOLqo=
|
|
||||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
|
||||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
|
||||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
|
||||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
|
||||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
|
||||||
github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
|
github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
|
||||||
github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
|
github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/vcaesar/cedar v0.20.2 h1:TDx7AdZhilKcfE1WvdToTJf5VrC/FXcUOW+KY1upLZ4=
|
|
||||||
github.com/vcaesar/cedar v0.20.2/go.mod h1:lyuGvALuZZDPNXwpzv/9LyxW+8Y6faN7zauFezNsnik=
|
|
||||||
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
|
|
||||||
github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU=
|
|
||||||
github.com/wailsapp/go-webview2 v1.0.19 h1:7U3QcDj1PrBPaxJNCui2k1SkWml+Q5kvFUFyTImA6NU=
|
github.com/wailsapp/go-webview2 v1.0.19 h1:7U3QcDj1PrBPaxJNCui2k1SkWml+Q5kvFUFyTImA6NU=
|
||||||
github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||||
@ -154,8 +142,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
|||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
@ -173,8 +161,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
|||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -199,8 +187,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@ -220,8 +208,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
146
main.go
146
main.go
@ -1,11 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"embed"
|
"embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/v2/slice"
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
@ -21,7 +20,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
goruntime "runtime"
|
goruntime "runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,13 +55,43 @@ var VersionCommit string
|
|||||||
func main() {
|
func main() {
|
||||||
checkDir("data")
|
checkDir("data")
|
||||||
db.Init("")
|
db.Init("")
|
||||||
go AutoMigrate()
|
db.Dao.AutoMigrate(&data.StockInfo{})
|
||||||
|
db.Dao.AutoMigrate(&data.StockBasic{})
|
||||||
|
db.Dao.AutoMigrate(&data.FollowedStock{})
|
||||||
|
db.Dao.AutoMigrate(&data.IndexBasic{})
|
||||||
|
db.Dao.AutoMigrate(&data.Settings{})
|
||||||
|
db.Dao.AutoMigrate(&models.AIResponseResult{})
|
||||||
|
db.Dao.AutoMigrate(&models.StockInfoHK{})
|
||||||
|
db.Dao.AutoMigrate(&models.StockInfoUS{})
|
||||||
|
db.Dao.AutoMigrate(&data.FollowedFund{})
|
||||||
|
db.Dao.AutoMigrate(&data.FundBasic{})
|
||||||
|
db.Dao.AutoMigrate(&models.PromptTemplate{})
|
||||||
|
db.Dao.AutoMigrate(&data.Group{})
|
||||||
|
db.Dao.AutoMigrate(&data.GroupStock{})
|
||||||
|
db.Dao.AutoMigrate(&models.Tags{})
|
||||||
|
db.Dao.AutoMigrate(&models.Telegraph{})
|
||||||
|
db.Dao.AutoMigrate(&models.TelegraphTags{})
|
||||||
|
|
||||||
//db.Dao.Model(&data.Group{}).Where("id = ?", 0).FirstOrCreate(&data.Group{
|
//db.Dao.Model(&data.Group{}).Where("id = ?", 0).FirstOrCreate(&data.Group{
|
||||||
// Name: "默认分组",
|
// Name: "默认分组",
|
||||||
// Sort: 0,
|
// Sort: 0,
|
||||||
//})
|
//})
|
||||||
|
|
||||||
|
if stocksBin != nil && len(stocksBin) > 0 {
|
||||||
|
go initStockData()
|
||||||
|
}
|
||||||
|
log.SugaredLogger.Infof("init stocksBinHK %d", len(stocksBinHK))
|
||||||
|
|
||||||
|
if stocksBinHK != nil && len(stocksBinHK) > 0 {
|
||||||
|
go initStockDataHK()
|
||||||
|
}
|
||||||
|
log.SugaredLogger.Infof("init stocksBinUS %d", len(stocksBinUS))
|
||||||
|
|
||||||
|
if stocksBinUS != nil && len(stocksBinUS) > 0 {
|
||||||
|
go initStockDataUS()
|
||||||
|
}
|
||||||
|
updateBasicInfo()
|
||||||
|
|
||||||
// Create an instance of the app structure
|
// Create an instance of the app structure
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
AppMenu := menu.NewMenu()
|
AppMenu := menu.NewMenu()
|
||||||
@ -186,30 +214,7 @@ func main() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func AutoMigrate() {
|
func initStockDataUS() {
|
||||||
db.Dao.AutoMigrate(&data.StockInfo{})
|
|
||||||
db.Dao.AutoMigrate(&data.StockBasic{})
|
|
||||||
db.Dao.AutoMigrate(&data.FollowedStock{})
|
|
||||||
db.Dao.AutoMigrate(&data.IndexBasic{})
|
|
||||||
db.Dao.AutoMigrate(&data.Settings{})
|
|
||||||
db.Dao.AutoMigrate(&models.AIResponseResult{})
|
|
||||||
db.Dao.AutoMigrate(&models.StockInfoHK{})
|
|
||||||
db.Dao.AutoMigrate(&models.StockInfoUS{})
|
|
||||||
db.Dao.AutoMigrate(&data.FollowedFund{})
|
|
||||||
db.Dao.AutoMigrate(&data.FundBasic{})
|
|
||||||
db.Dao.AutoMigrate(&models.PromptTemplate{})
|
|
||||||
db.Dao.AutoMigrate(&data.Group{})
|
|
||||||
db.Dao.AutoMigrate(&data.GroupStock{})
|
|
||||||
db.Dao.AutoMigrate(&models.Tags{})
|
|
||||||
db.Dao.AutoMigrate(&models.Telegraph{})
|
|
||||||
db.Dao.AutoMigrate(&models.TelegraphTags{})
|
|
||||||
db.Dao.AutoMigrate(&models.LongTigerRankData{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func initStockDataUS(ctx context.Context) {
|
|
||||||
defer func() {
|
|
||||||
go runtime.EventsEmit(ctx, "loadingMsg", "done")
|
|
||||||
}()
|
|
||||||
var v []models.StockInfoUS
|
var v []models.StockInfoUS
|
||||||
err := json.Unmarshal(stocksBinUS, &v)
|
err := json.Unmarshal(stocksBinUS, &v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -217,9 +222,6 @@ func initStockDataUS(ctx context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.SugaredLogger.Infof("init stock data us %d", len(v))
|
log.SugaredLogger.Infof("init stock data us %d", len(v))
|
||||||
var total int64
|
|
||||||
db.Dao.Model(&models.StockInfoUS{}).Count(&total)
|
|
||||||
if total != int64(len(v)) {
|
|
||||||
for _, item := range v {
|
for _, item := range v {
|
||||||
var count int64
|
var count int64
|
||||||
db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", item.Code).Count(&count)
|
db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", item.Code).Count(&count)
|
||||||
@ -230,12 +232,8 @@ func initStockDataUS(ctx context.Context) {
|
|||||||
db.Dao.Model(&models.StockInfoUS{}).Create(&item)
|
db.Dao.Model(&models.StockInfoUS{}).Create(&item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func initStockDataHK(ctx context.Context) {
|
func initStockDataHK() {
|
||||||
defer func() {
|
|
||||||
go runtime.EventsEmit(ctx, "loadingMsg", "done")
|
|
||||||
}()
|
|
||||||
var v []models.StockInfoHK
|
var v []models.StockInfoHK
|
||||||
err := json.Unmarshal(stocksBinHK, &v)
|
err := json.Unmarshal(stocksBinHK, &v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -243,9 +241,6 @@ func initStockDataHK(ctx context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.SugaredLogger.Infof("init stock data hk %d", len(v))
|
log.SugaredLogger.Infof("init stock data hk %d", len(v))
|
||||||
var total int64
|
|
||||||
db.Dao.Model(&models.StockInfoHK{}).Count(&total)
|
|
||||||
if total != int64(len(v)) {
|
|
||||||
for _, item := range v {
|
for _, item := range v {
|
||||||
var count int64
|
var count int64
|
||||||
db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", item.Code).Count(&count)
|
db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", item.Code).Count(&count)
|
||||||
@ -257,8 +252,6 @@ func initStockDataHK(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateBasicInfo() {
|
func updateBasicInfo() {
|
||||||
config := data.NewSettingsApi(&data.Settings{}).GetConfig()
|
config := data.NewSettingsApi(&data.Settings{}).GetConfig()
|
||||||
if config.UpdateBasicInfoOnStart {
|
if config.UpdateBasicInfoOnStart {
|
||||||
@ -268,11 +261,7 @@ func updateBasicInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initStockData(ctx context.Context) {
|
func initStockData() {
|
||||||
defer func() {
|
|
||||||
go runtime.EventsEmit(ctx, "loadingMsg", "done")
|
|
||||||
}()
|
|
||||||
fields := "ts_code,symbol,name,area,industry,cnspell,market,list_date,act_name,act_ent_type,fullname,exchange,list_status,curr_type,enname,delist_date,is_hs"
|
|
||||||
log.SugaredLogger.Info("init stock data")
|
log.SugaredLogger.Info("init stock data")
|
||||||
res := &data.TushareStockBasicResponse{}
|
res := &data.TushareStockBasicResponse{}
|
||||||
err := json.Unmarshal(stocksBin, res)
|
err := json.Unmarshal(stocksBin, res)
|
||||||
@ -280,24 +269,26 @@ func initStockData(ctx context.Context) {
|
|||||||
log.SugaredLogger.Error(err.Error())
|
log.SugaredLogger.Error(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range res.Data.Items {
|
for _, item := range res.Data.Items {
|
||||||
stock := &data.StockBasic{}
|
stock := &data.StockBasic{}
|
||||||
stockData := map[string]any{}
|
stock.Exchange = convertor.ToString(item[0])
|
||||||
for _, field := range strings.Split(fields, ",") {
|
stock.IsHs = convertor.ToString(item[1])
|
||||||
//logger.SugaredLogger.Infof("field: %s", field)
|
stock.Name = convertor.ToString(item[2])
|
||||||
idx := slice.IndexOf(res.Data.Fields, field)
|
stock.Industry = convertor.ToString(item[3])
|
||||||
if idx == -1 {
|
stock.ListStatus = convertor.ToString(item[4])
|
||||||
continue
|
stock.ActName = convertor.ToString(item[5])
|
||||||
}
|
stock.ID = uint(item[6].(float64))
|
||||||
stockData[field] = item[idx]
|
stock.CurrType = convertor.ToString(item[7])
|
||||||
}
|
stock.Area = convertor.ToString(item[8])
|
||||||
jsonData, _ := json.Marshal(stockData)
|
stock.ListDate = convertor.ToString(item[9])
|
||||||
err := json.Unmarshal(jsonData, stock)
|
stock.DelistDate = convertor.ToString(item[10])
|
||||||
if err != nil {
|
stock.ActEntType = convertor.ToString(item[11])
|
||||||
continue
|
stock.TsCode = convertor.ToString(item[12])
|
||||||
}
|
stock.Symbol = convertor.ToString(item[13])
|
||||||
stock.ID = 0
|
stock.Cnspell = convertor.ToString(item[14])
|
||||||
|
stock.Fullname = convertor.ToString(item[20])
|
||||||
|
stock.Ename = convertor.ToString(item[21])
|
||||||
|
|
||||||
var count int64
|
var count int64
|
||||||
db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).Count(&count)
|
db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).Count(&count)
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
@ -305,38 +296,7 @@ func initStockData(ctx context.Context) {
|
|||||||
} else {
|
} else {
|
||||||
db.Dao.Create(stock)
|
db.Dao.Create(stock)
|
||||||
}
|
}
|
||||||
|
|
||||||
//db.Dao.Model(&data.StockBasic{}).FirstOrCreate(stock, &data.StockBasic{TsCode: stock.TsCode}).Where("ts_code = ?", stock.TsCode).Updates(stock)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//for _, item := range res.Data.Items {
|
|
||||||
// stock := &data.StockBasic{}
|
|
||||||
// stock.Exchange = convertor.ToString(item[0])
|
|
||||||
// stock.IsHs = convertor.ToString(item[1])
|
|
||||||
// stock.Name = convertor.ToString(item[2])
|
|
||||||
// stock.Industry = convertor.ToString(item[3])
|
|
||||||
// stock.ListStatus = convertor.ToString(item[4])
|
|
||||||
// stock.ActName = convertor.ToString(item[5])
|
|
||||||
// stock.ID = uint(item[6].(float64))
|
|
||||||
// stock.CurrType = convertor.ToString(item[7])
|
|
||||||
// stock.Area = convertor.ToString(item[8])
|
|
||||||
// stock.ListDate = convertor.ToString(item[9])
|
|
||||||
// stock.DelistDate = convertor.ToString(item[10])
|
|
||||||
// stock.ActEntType = convertor.ToString(item[11])
|
|
||||||
// stock.TsCode = convertor.ToString(item[12])
|
|
||||||
// stock.Symbol = convertor.ToString(item[13])
|
|
||||||
// stock.Cnspell = convertor.ToString(item[14])
|
|
||||||
// stock.Fullname = convertor.ToString(item[20])
|
|
||||||
// stock.Ename = convertor.ToString(item[21])
|
|
||||||
//
|
|
||||||
// var count int64
|
|
||||||
// db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).Count(&count)
|
|
||||||
// if count > 0 {
|
|
||||||
// continue
|
|
||||||
// } else {
|
|
||||||
// db.Dao.Create(stock)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkDir(dir string) {
|
func checkDir(dir string) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user