feat(market):添加行业排名功能

- 在市场行情模块中增加行业排名标签页
- 实现行业排名数据的获取和展示- 添加行业排名相关的图标和交互
- 优化市场行情模块的结构和样式
This commit is contained in:
ArvinLovegood 2025-05-13 23:11:36 +08:00
parent c7e37e039e
commit ae9f4073dc
9 changed files with 221 additions and 12 deletions

4
app.go
View File

@ -1103,3 +1103,7 @@ func (a *App) SummaryStockNews(question string, sysPromptId *int) {
}
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)
}

View File

@ -224,3 +224,16 @@ func (m MarketNewsApi) GlobalStockIndexes(crawlTimeOut uint) map[string]any {
json.Unmarshal([]byte(js), &res)
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
}

View File

@ -27,3 +27,11 @@ func TestGlobalStockIndexes(t *testing.T) {
}
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)
}
}

View File

@ -15,7 +15,15 @@ import {
SettingsOutline,
ReorderTwoOutline,
ExpandOutline,
PowerOutline, LogoGithub, MoveOutline, WalletOutline, StarOutline, AlarmOutline, SparklesOutline, NewspaperOutline,
PowerOutline,
LogoGithub,
MoveOutline,
WalletOutline,
StarOutline,
AlarmOutline,
SparklesOutline,
NewspaperOutline,
AnalyticsOutline, BarChartSharp, NewspaperSharp, Flame,
} from '@vicons/ionicons5'
import {GetConfig, GetGroupList} from "../wailsjs/go/main/App";
import { useRouter } from 'vue-router'
@ -90,16 +98,106 @@ const menuOptions = ref([
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(Flame),
}
]
},
{
label: () =>

View File

@ -4,7 +4,7 @@
import 'md-editor-v3/lib/preview.css';
import {h, onBeforeUnmount, onMounted, ref} from 'vue';
import {CheckUpdate, GetVersionInfo} from "../../wailsjs/go/main/App";
import {EventsOn} from "../../wailsjs/runtime";
import {EventsOff, EventsOn} from "../../wailsjs/runtime";
import {NAvatar, NButton, useNotification} from "naive-ui";
const updateLog = ref('');
const versionInfo = ref('');
@ -25,6 +25,7 @@ onMounted(() => {
})
onBeforeUnmount(() => {
notify.destroyAll()
EventsOff("updateVersion")
})
EventsOn("updateVersion",async (msg) => {

View File

@ -1,20 +1,22 @@
<script setup>
import {computed, h, onBeforeMount, ref} from 'vue'
import {computed, h, onBeforeMount, onBeforeUnmount, ref} from 'vue'
import {
GetAIResponseResult,
GetConfig, GetPromptTemplates,
GetConfig, GetIndustryRank, GetPromptTemplates,
GetTelegraphList,
GlobalStockIndexes, ReFleshTelegraphList,
SaveAIResponseResult, SaveAsMarkdown, ShareAnalysis,
SummaryStockNews
} from "../../wailsjs/go/main/App";
import {EventsOn} from "../../wailsjs/runtime";
import {EventsOff, EventsOn} from "../../wailsjs/runtime";
import NewsList from "./newsList.vue";
import KLineChart from "./KLineChart.vue";
import {Add, ChatboxOutline, PulseOutline,} from "@vicons/ionicons5";
import {Add, CaretDown, CaretUp, ChatboxOutline, PulseOutline,} from "@vicons/ionicons5";
import {NAvatar, NButton, NFlex, NText, useMessage, useNotification} from "naive-ui";
import {ExportPDF} from "@vavt/v3-extension";
import {MdEditor, MdPreview} from "md-editor-v3";
import { useRoute } from 'vue-router'
const route = useRoute()
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
const message = useMessage()
@ -46,7 +48,10 @@ const loading=ref(true)
const sysPromptOptions=ref([])
const userPromptOptions=ref([])
const promptTemplates=ref([])
const industryRanks=ref([])
const sort = ref("")
const sortIcon= ref(h(CaretDown))
const nowTab=ref("市场快讯")
function getIndex() {
GlobalStockIndexes().then((res) => {
globalStockIndexes.value = res
@ -59,6 +64,7 @@ function getIndex() {
}
onBeforeMount(() => {
nowTab.value=route.query.name
GetConfig().then(result => {
summaryBTN.value= result.openAiEnable
darkTheme.value = result.darkTheme
@ -76,13 +82,27 @@ onBeforeMount(() => {
sinaNewsList.value = res
})
getIndex();
industryRank();
setInterval(() => {
getIndex()
}, 3000)
setInterval(() => {
industryRank()
},1000*10)
})
onBeforeUnmount(() => {
EventsOff("changeMarketTab")
EventsOff("newTelegraph")
EventsOff("newSinaNews")
EventsOff("summaryStockNews")
})
EventsOn("changeMarketTab" ,async (msg) => {
//message.info(msg.name)
updateTab(msg.name)
})
EventsOn("newTelegraph", (data) => {
for (let i = 0; i < data.length; i++) {
@ -116,6 +136,22 @@ function getAreaName(code){
return "其他"
}
}
function industryRank(){
if(sort.value==="0"){
sort.value="1"
}else{
sort.value="0"
}
GetIndustryRank(sort.value,150).then(result => {
if(result.length>0){
console.log(result)
industryRanks.value = result
}else{
message.info("暂无数据")
}
})
}
function reAiSummary(){
aiSummary.value=""
summaryModal.value = true
@ -151,6 +187,7 @@ function getAiSummary(){
function updateTab(name) {
summaryBTN.value = (name === "市场快讯");
nowTab.value = name
}
EventsOn("summaryStockNews",async (msg) => {
@ -235,7 +272,7 @@ function ReFlesh(source){
<template>
<n-card>
<n-tabs type="line" animated @update-value="updateTab">
<n-tabs type="line" animated @update-value="updateTab" :value="nowTab" >
<n-tab-pane name="市场快讯" tab="市场快讯" >
<n-grid :cols="2" :y-gap="0">
<n-gi>
@ -344,6 +381,32 @@ function ReFlesh(source){
</n-tab-pane>
</n-tabs>
</n-tab-pane>
<n-tab-pane name="行业排名" tab="行业排名">
<n-table striped>
<n-thead>
<n-tr>
<n-th>行业名称</n-th>
<n-th @click="industryRank">行业涨幅<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></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-tabs>
</n-card>
<n-modal transform-origin="center" v-model:show="summaryModal" preset="card" style="width: 800px;" :title="'AI市场资讯总结'" >

View File

@ -38,7 +38,14 @@ import {
useModal,
useNotification
} from 'naive-ui'
import {EventsEmit, EventsOn, WindowFullscreen, WindowReload, WindowUnfullscreen} from '../../wailsjs/runtime'
import {
EventsEmit,
EventsOff,
EventsOn,
WindowFullscreen,
WindowReload,
WindowUnfullscreen
} from '../../wailsjs/runtime'
import {
Add,
ChatboxOutline,
@ -262,6 +269,15 @@ onBeforeUnmount(() => {
message.destroyAll()
notify.destroyAll()
clearInterval(feishiInterval.value)
EventsOff("refresh")
EventsOff("showSearch")
EventsOff("stock_price")
EventsOff("refreshFollowList")
EventsOff("newChatStream")
EventsOff("changeTab")
EventsOff("updateVersion")
EventsOff("warnMsg")
})
EventsOn("refresh",(data)=>{
@ -1572,7 +1588,7 @@ function delStockGroup(code,name,groupId){
</n-gradient-text>
</template>
</vue-danmaku>
<n-tabs style="--wails-draggable:drag" type="card" animated addable :data-currentGroupId="currentGroupId" :value="currentGroupId" @add="addTab" @update-value="updateTab" placement="top" @close="(key)=>{delTab(key)}">
<n-tabs type="card" style="--wails-draggable:drag" animated addable :data-currentGroupId="currentGroupId" :value="currentGroupId" @add="addTab" @update-value="updateTab" placement="top" @close="(key)=>{delTab(key)}">
<n-tab-pane :name="0" :tab="'全部'">
<n-grid :x-gap="8" :cols="3" :y-gap="8" >
<n-gi :id="result['股票代码']+'_gi'" v-for="result in sortedResults" style="margin-left: 2px;" >

View File

@ -33,6 +33,8 @@ export function GetGroupList():Promise<Array<data.Group>>;
export function GetGroupStockList(arg1:number):Promise<Array<data.GroupStock>>;
export function GetIndustryRank(arg1:string,arg2:number):Promise<Array<any>>;
export function GetPromptTemplates(arg1:string,arg2:string):Promise<any>;
export function GetStockCommonKLine(arg1:string,arg2:string,arg3:number):Promise<any>;

View File

@ -62,6 +62,10 @@ export function GetGroupStockList(arg1) {
return window['go']['main']['App']['GetGroupStockList'](arg1);
}
export function GetIndustryRank(arg1, arg2) {
return window['go']['main']['App']['GetIndustryRank'](arg1, arg2);
}
export function GetPromptTemplates(arg1, arg2) {
return window['go']['main']['App']['GetPromptTemplates'](arg1, arg2);
}