mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(frontend):添加市场资讯功能
- 新增市场资讯页面,用于展示财经新闻 - 实现电报列表获取和实时更新功能 - 添加新闻标签和股票标签显示 - 优化新闻列表展示样式
This commit is contained in:
parent
3a74e0ed98
commit
6be23d6abc
14
app.go
14
app.go
@ -160,6 +160,15 @@ func (a *App) domReady(ctx context.Context) {
|
||||
} else {
|
||||
a.cronEntrys["MonitorStockPrices"] = id
|
||||
}
|
||||
entryID, err := a.cron.AddFunc(fmt.Sprintf("@every %ds", interval+10), func() {
|
||||
news := data.GetNewTelegraph(30)
|
||||
go runtime.EventsEmit(a.ctx, "newTelegraph", news)
|
||||
})
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("AddFunc error:%s", err.Error())
|
||||
} else {
|
||||
a.cronEntrys["GetNewTelegraph"] = entryID
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
@ -1047,3 +1056,8 @@ func (a *App) RemoveGroup(groupId int) string {
|
||||
func (a *App) GetStockKLine(stockCode, stockName string, days int64) *[]data.KLineData {
|
||||
return data.NewStockDataApi().GetHK_KLineData(stockCode, "day", days)
|
||||
}
|
||||
|
||||
func (a *App) GetTelegraphList() *[]*models.Telegraph {
|
||||
telegraphs := data.NewMarketNewsApi().GetTelegraphList()
|
||||
return telegraphs
|
||||
}
|
||||
|
36
backend/data/market_news_api.go
Normal file
36
backend/data/market_news_api.go
Normal file
@ -0,0 +1,36 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"github.com/samber/lo"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"go-stock/backend/models"
|
||||
)
|
||||
|
||||
// @Author spark
|
||||
// @Date 2025/4/23 14:54
|
||||
// @Desc
|
||||
// -----------------------------------------------------------------------------------
|
||||
type MarketNewsApi struct {
|
||||
}
|
||||
|
||||
func NewMarketNewsApi() *MarketNewsApi {
|
||||
return &MarketNewsApi{}
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) GetTelegraphList() *[]*models.Telegraph {
|
||||
news := &[]*models.Telegraph{}
|
||||
db.Dao.Model(news).Preload("TelegraphTags").Order("id desc").Limit(20).Find(news)
|
||||
for _, item := range *news {
|
||||
tags := &[]models.Tags{}
|
||||
db.Dao.Model(&models.Tags{}).Where("id in ?", lo.Map(item.TelegraphTags, func(item models.TelegraphTags, index int) uint {
|
||||
return item.TagId
|
||||
})).Find(&tags)
|
||||
tagNames := lo.Map(*tags, func(item models.Tags, index int) string {
|
||||
return item.Name
|
||||
})
|
||||
item.SubjectTags = tagNames
|
||||
logger.SugaredLogger.Infof("tagNames %v ,SubjectTags:%s", tagNames, item.SubjectTags)
|
||||
}
|
||||
return news
|
||||
}
|
@ -716,6 +716,70 @@ func GetTelegraphList(crawlTimeOut int64) *[]string {
|
||||
return &telegraph
|
||||
}
|
||||
|
||||
func GetNewTelegraph(crawlTimeOut int64) *[]models.Telegraph {
|
||||
url := "https://www.cls.cn/telegraph"
|
||||
response, _ := resty.New().SetTimeout(time.Duration(crawlTimeOut)*time.Second).R().
|
||||
SetHeader("Referer", "https://www.cls.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(fmt.Sprintf(url))
|
||||
var telegraphs []models.Telegraph
|
||||
//logger.SugaredLogger.Info(string(response.Body()))
|
||||
document, _ := goquery.NewDocumentFromReader(strings.NewReader(string(response.Body())))
|
||||
|
||||
document.Find(".telegraph-list").Each(func(i int, selection *goquery.Selection) {
|
||||
//logger.SugaredLogger.Info(selection.Text())
|
||||
telegraph := models.Telegraph{}
|
||||
spans := selection.Find("div.telegraph-content-box span")
|
||||
if spans.Length() == 2 {
|
||||
telegraph.Time = spans.First().Text()
|
||||
telegraph.Content = spans.Last().Text()
|
||||
if spans.Last().HasClass("c-de0422") {
|
||||
telegraph.IsRed = true
|
||||
}
|
||||
}
|
||||
|
||||
labels := selection.Find("div a.label-item")
|
||||
labels.Each(func(i int, selection *goquery.Selection) {
|
||||
if selection.HasClass("link-label-item") {
|
||||
telegraph.Url = selection.AttrOr("href", "")
|
||||
} else {
|
||||
tag := &models.Tags{
|
||||
Name: selection.Text(),
|
||||
Type: "subject",
|
||||
}
|
||||
db.Dao.Model(tag).Where("name=? and type=?", selection.Text(), "subject").FirstOrCreate(&tag)
|
||||
telegraph.SubjectTags = append(telegraph.SubjectTags, selection.Text())
|
||||
}
|
||||
})
|
||||
stocks := selection.Find("div.telegraph-stock-plate-box a")
|
||||
stocks.Each(func(i int, selection *goquery.Selection) {
|
||||
telegraph.StocksTags = append(telegraph.StocksTags, selection.Text())
|
||||
})
|
||||
|
||||
//telegraph = append(telegraph, ReplaceSensitiveWords(selection.Text()))
|
||||
if telegraph.Content != "" {
|
||||
cnt := int64(0)
|
||||
db.Dao.Model(telegraph).Where("time=?", telegraph.Time).Count(&cnt)
|
||||
if cnt == 0 {
|
||||
db.Dao.Create(&telegraph)
|
||||
telegraphs = append(telegraphs, telegraph)
|
||||
for _, tag := range telegraph.SubjectTags {
|
||||
tagInfo := &models.Tags{}
|
||||
db.Dao.Model(models.Tags{}).Where("name=? and type=?", tag, "subject").First(&tagInfo)
|
||||
if tagInfo.ID > 0 {
|
||||
db.Dao.Model(models.TelegraphTags{}).Where("telegraph_id=? and tag_id=?", telegraph.ID, tagInfo.ID).FirstOrCreate(&models.TelegraphTags{
|
||||
TelegraphId: telegraph.ID,
|
||||
TagId: tagInfo.ID,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
return &telegraphs
|
||||
}
|
||||
|
||||
func GetTopNewsList(crawlTimeOut int64) *[]string {
|
||||
url := "https://www.cls.cn"
|
||||
response, err := resty.New().SetTimeout(time.Duration(crawlTimeOut)*time.Second).R().
|
||||
|
@ -22,7 +22,16 @@ import (
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
func TestGetTelegraph(t *testing.T) {
|
||||
GetTelegraphList(30)
|
||||
db.Init("../../data/stock.db")
|
||||
|
||||
//telegraphs := GetTelegraphList(30)
|
||||
//for _, telegraph := range *telegraphs {
|
||||
// logger.SugaredLogger.Info(telegraph)
|
||||
//}
|
||||
list := GetNewTelegraph(30)
|
||||
for _, telegraph := range *list {
|
||||
logger.SugaredLogger.Infof("telegraph:%+v", telegraph)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFinancialReports(t *testing.T) {
|
||||
|
@ -215,3 +215,37 @@ type Prompt struct {
|
||||
Content string `json:"content"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type Telegraph struct {
|
||||
gorm.Model
|
||||
Time string `json:"time"`
|
||||
Content string `json:"content"`
|
||||
SubjectTags []string `json:"subjects" gorm:"-:all"`
|
||||
StocksTags []string `json:"stocks" gorm:"-:all"`
|
||||
IsRed bool `json:"isRed"`
|
||||
Url string `json:"url"`
|
||||
TelegraphTags []TelegraphTags `json:"tags" gorm:"-:migration;foreignKey:TelegraphId"`
|
||||
}
|
||||
type TelegraphTags struct {
|
||||
gorm.Model
|
||||
TagId uint `json:"tagId"`
|
||||
TelegraphId uint `json:"telegraphId"`
|
||||
}
|
||||
|
||||
func (t TelegraphTags) TableName() string {
|
||||
return "telegraph_tags"
|
||||
}
|
||||
|
||||
type Tags struct {
|
||||
gorm.Model
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func (p Tags) TableName() string {
|
||||
return "tags"
|
||||
}
|
||||
|
||||
func (p Telegraph) TableName() string {
|
||||
return "telegraph_list"
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
SettingsOutline,
|
||||
ReorderTwoOutline,
|
||||
ExpandOutline,
|
||||
PowerOutline, LogoGithub, MoveOutline, WalletOutline, StarOutline, AlarmOutline, SparklesOutline,
|
||||
PowerOutline, LogoGithub, MoveOutline, WalletOutline, StarOutline, AlarmOutline, SparklesOutline, NewspaperOutline,
|
||||
} from '@vicons/ionicons5'
|
||||
import {GetConfig} from "../wailsjs/go/main/App";
|
||||
const enableNews= ref(false)
|
||||
@ -53,6 +53,22 @@ const menuOptions = ref([
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
RouterLink,
|
||||
{
|
||||
to: {
|
||||
name: 'market',
|
||||
params: {
|
||||
}
|
||||
}
|
||||
},
|
||||
{ default: () => '市场资讯' }
|
||||
),
|
||||
key: 'market',
|
||||
icon: renderIcon(NewspaperOutline),
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
@ -246,7 +262,7 @@ onMounted(()=>{
|
||||
:y-offset="150"
|
||||
:rotate="-15"
|
||||
>
|
||||
<n-flex justify="center">
|
||||
<n-flex>
|
||||
<n-grid x-gap="12" :cols="1">
|
||||
<!--
|
||||
<n-gi style="position: relative;top:1px;z-index: 19;width: 100%" v-if="telegraph.length>0">
|
||||
|
71
frontend/src/components/market.vue
Normal file
71
frontend/src/components/market.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<script setup>
|
||||
import {computed, h, onBeforeMount, onBeforeUnmount, onMounted, reactive, ref} from 'vue'
|
||||
import {
|
||||
NFlex,
|
||||
NTimeline,
|
||||
NTimelineItem,
|
||||
} from 'naive-ui'
|
||||
import * as echarts from 'echarts';
|
||||
import {GetTelegraphList} from "../../wailsjs/go/main/App";
|
||||
import {EventsOn} from "../../wailsjs/runtime";
|
||||
|
||||
const telegraphList= ref([])
|
||||
onBeforeMount(() => {
|
||||
GetTelegraphList().then((res) => {
|
||||
telegraphList.value = res
|
||||
})
|
||||
})
|
||||
|
||||
EventsOn("newTelegraph", (data) => {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
telegraphList.value.pop()
|
||||
}
|
||||
telegraphList.value.unshift(...data)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-grid :cols="2" :y-gap="6">
|
||||
<!-- <n-gi>-->
|
||||
<!-- <n-card title="上证指数">-->
|
||||
<!-- 卡片内容-->
|
||||
<!-- </n-card>-->
|
||||
<!-- </n-gi>-->
|
||||
<!-- <n-gi>-->
|
||||
<!-- <n-card title="深证成指">-->
|
||||
<!-- 卡片内容-->
|
||||
<!-- </n-card>-->
|
||||
<!-- </n-gi>-->
|
||||
<n-gi span="2">
|
||||
<n-flex justify="flex-start">
|
||||
<n-list bordered>
|
||||
<template #header>
|
||||
财联社电报
|
||||
</template>
|
||||
<n-list-item v-for="item in telegraphList" >
|
||||
<n-space justify="start">
|
||||
<n-text :bordered="false" :type="item.isRed?'error':'info'"> <n-tag size="small" :type="item.isRed?'error':'warning'" :bordered="false"> {{item.time}}</n-tag>{{item.content}}</n-text>
|
||||
</n-space>
|
||||
<n-space v-if="item.subjects" style="margin-top: 2px">
|
||||
<n-tag :bordered="false" type="success" size="small" v-for="sub in item.subjects">
|
||||
{{sub}}
|
||||
</n-tag>
|
||||
<n-space v-if="item.stocks">
|
||||
<n-tag :bordered="false" type="warning" size="small" v-for="sub in item.stocks">
|
||||
{{sub}}
|
||||
</n-tag>
|
||||
</n-space>
|
||||
<n-tag v-if="item.url" :bordered="false" type="warning" size="small" >
|
||||
<a :href="item.url" target="_blank" ><n-text type="warning">查看原文</n-text></a>
|
||||
</n-tag>
|
||||
</n-space>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</n-flex>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -4,12 +4,14 @@ import stockView from '../components/stock.vue'
|
||||
import settingsView from '../components/settings.vue'
|
||||
import about from "../components/about.vue";
|
||||
import fundView from "../components/fund.vue";
|
||||
import market from "../components/market.vue";
|
||||
|
||||
const routes = [
|
||||
{ path: '/', component: stockView,name: 'stock' },
|
||||
{ path: '/fund', component: fundView,name: 'fund' },
|
||||
{ path: '/settings', component: settingsView,name: 'settings' },
|
||||
{ path: '/about', component: about,name: 'about' },
|
||||
{ path: '/market', component: market,name: 'market' },
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
|
2
frontend/wailsjs/go/main/App.d.ts
vendored
2
frontend/wailsjs/go/main/App.d.ts
vendored
@ -39,6 +39,8 @@ export function GetStockKLine(arg1:string,arg2:string,arg3:number):Promise<any>;
|
||||
|
||||
export function GetStockList(arg1:string):Promise<Array<data.StockBasic>>;
|
||||
|
||||
export function GetTelegraphList():Promise<any>;
|
||||
|
||||
export function GetVersionInfo():Promise<models.VersionInfo>;
|
||||
|
||||
export function GetfundList(arg1:string):Promise<Array<data.FundBasic>>;
|
||||
|
@ -74,6 +74,10 @@ export function GetStockList(arg1) {
|
||||
return window['go']['main']['App']['GetStockList'](arg1);
|
||||
}
|
||||
|
||||
export function GetTelegraphList() {
|
||||
return window['go']['main']['App']['GetTelegraphList']();
|
||||
}
|
||||
|
||||
export function GetVersionInfo() {
|
||||
return window['go']['main']['App']['GetVersionInfo']();
|
||||
}
|
||||
|
31
main.go
31
main.go
@ -68,26 +68,29 @@ func main() {
|
||||
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{
|
||||
// Name: "默认分组",
|
||||
// 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()
|
||||
//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
|
||||
app := NewApp()
|
||||
|
Loading…
x
Reference in New Issue
Block a user