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
4fd5cbf8e6
commit
2a274db7ae
5
app.go
5
app.go
@ -1131,3 +1131,8 @@ 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)
|
||||
return res
|
||||
}
|
||||
|
@ -275,3 +275,21 @@ func (m MarketNewsApi) GetMoneyRankSina(sort string) []map[string]any {
|
||||
}
|
||||
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
|
||||
|
||||
}
|
||||
|
@ -49,3 +49,10 @@ func TestGetMoneyRankSina(t *testing.T) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStockMoneyTrendByDay(t *testing.T) {
|
||||
res := NewMarketNewsApi().GetStockMoneyTrendByDay("sh600438", 120)
|
||||
for i, re := range res {
|
||||
logger.SugaredLogger.Debugf("key: %+v, value: %+v", i, re)
|
||||
}
|
||||
}
|
||||
|
@ -446,7 +446,7 @@ onBeforeMount(() => {
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
contentStyle.value = "max-height: calc(90vh);overflow: hidden"
|
||||
contentStyle.value = "max-height: calc(92vh);overflow: hidden"
|
||||
GetConfig().then((res) => {
|
||||
if (res.enableNews) {
|
||||
enableNews.value = true
|
||||
@ -488,6 +488,7 @@ onMounted(() => {
|
||||
</n-tag>
|
||||
</n-marquee>
|
||||
<n-scrollbar :style="contentStyle">
|
||||
<n-skeleton v-if="loading" height="calc(100vh)" />
|
||||
<RouterView/>
|
||||
</n-scrollbar>
|
||||
</n-spin>
|
||||
|
279
frontend/src/components/moneyTrend.vue
Normal file
279
frontend/src/components/moneyTrend.vue
Normal file
@ -0,0 +1,279 @@
|
||||
<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 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)
|
||||
|
||||
if (min === 0 || min > price) {
|
||||
min = price
|
||||
}
|
||||
if (max < price) {
|
||||
max = price
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
let b=(result[i].netamount - result[i - 1].netamount)/10000
|
||||
volume.push(b)
|
||||
} else {
|
||||
volume.push(result[i].netamount/10000)
|
||||
}
|
||||
|
||||
}
|
||||
console.log("trades_values", trades_values)
|
||||
|
||||
let option = {
|
||||
darkMode: darkTheme,
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
animation: false,
|
||||
label: {
|
||||
backgroundColor: '#505765'
|
||||
}
|
||||
}
|
||||
},
|
||||
axisPointer: {
|
||||
link: [
|
||||
{
|
||||
xAxisIndex: 'all'
|
||||
}
|
||||
],
|
||||
label: {
|
||||
backgroundColor: '#888'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
data: ['当日净流入','累计净流入', '股价'],
|
||||
selected: {
|
||||
'当日净流入': true,
|
||||
'累计净流入': false,
|
||||
'股价': true,
|
||||
},
|
||||
//orient: 'vertical',
|
||||
textStyle: {
|
||||
color: darkTheme ? '#ccc' : '#456'
|
||||
},
|
||||
right: 150,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
show: true,
|
||||
realtime: true,
|
||||
start: 70,
|
||||
end: 100
|
||||
},
|
||||
{
|
||||
type: 'inside',
|
||||
realtime: true,
|
||||
start: 86,
|
||||
end: 100
|
||||
}
|
||||
],
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: categoryData
|
||||
},
|
||||
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
|
||||
},
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '当日净流入',
|
||||
data: netamount_values,
|
||||
smooth: true,
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
width: 2
|
||||
},
|
||||
markPoint: {
|
||||
symbol: 'arrow',
|
||||
symbolRotate: 90,
|
||||
symbolSize: [10, 20],
|
||||
symbolOffset: [10, 0],
|
||||
itemStyle: {
|
||||
color: '#FC290D'
|
||||
},
|
||||
label: {
|
||||
position: 'right',
|
||||
},
|
||||
data: [
|
||||
{type: 'max', name: 'Max'},
|
||||
{type: 'min', name: 'Min'}
|
||||
]
|
||||
},
|
||||
markLine: {
|
||||
data: [
|
||||
{
|
||||
type: 'average',
|
||||
name: 'Average',
|
||||
lineStyle: {
|
||||
color: '#ff001e',
|
||||
width: 0.5
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
type: 'line'
|
||||
},
|
||||
{
|
||||
name: '累计净流入',
|
||||
data: volume,
|
||||
smooth: true,
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
width: 2
|
||||
},
|
||||
markPoint: {
|
||||
symbol: 'arrow',
|
||||
symbolRotate: 90,
|
||||
symbolSize: [10, 20],
|
||||
symbolOffset: [10, 0],
|
||||
itemStyle: {
|
||||
color: '#FC290D'
|
||||
},
|
||||
label: {
|
||||
position: 'right',
|
||||
},
|
||||
data: [
|
||||
{type: 'max', name: 'Max'},
|
||||
{type: 'min', name: 'Min'}
|
||||
]
|
||||
},
|
||||
markLine: {
|
||||
data: [
|
||||
{
|
||||
type: 'average',
|
||||
name: 'Average',
|
||||
lineStyle: {
|
||||
color: '#ff001e',
|
||||
width: 0.5
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
type: 'line'
|
||||
},
|
||||
{
|
||||
name: '股价',
|
||||
type: 'line',
|
||||
data: trades_values,
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
width: 3
|
||||
},
|
||||
markPoint: {
|
||||
symbol: 'arrow',
|
||||
symbolRotate: 90,
|
||||
symbolSize: [10, 20],
|
||||
symbolOffset: [10, 0],
|
||||
itemStyle: {
|
||||
color: '#0940f3'
|
||||
},
|
||||
label: {
|
||||
position: 'right',
|
||||
},
|
||||
data: [
|
||||
{type: 'max', name: 'Max'},
|
||||
{type: 'min', name: 'Min'}
|
||||
]
|
||||
},
|
||||
markLine: {
|
||||
data: [
|
||||
{
|
||||
type: 'average',
|
||||
name: 'Average',
|
||||
lineStyle: {
|
||||
color: '#0940f3',
|
||||
width: 0.5
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
]
|
||||
};
|
||||
chart.setOption(option);
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="LineChartRef" style="width: 100%;height: auto;" :style="{height:chartHeight+'px'}"></div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -63,6 +63,7 @@ import {asBlob} from 'html-docx-js-typescript';
|
||||
import vueDanmaku from 'vue3-danmaku'
|
||||
import {keys, pad, padStart} from "lodash";
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import MoneyTrend from "./moneyTrend.vue";
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
@ -98,6 +99,7 @@ const modalShow = ref(false)
|
||||
const modalShow2 = ref(false)
|
||||
const modalShow3 = ref(false)
|
||||
const modalShow4 = ref(false)
|
||||
const modalShow5 = ref(false)
|
||||
const addBTN = ref(true)
|
||||
const formModel = ref({
|
||||
name: "",
|
||||
@ -1241,6 +1243,12 @@ function handleKLine(){
|
||||
});
|
||||
})
|
||||
}
|
||||
function showMoney(code,name){
|
||||
data.code=code
|
||||
data.name=name
|
||||
modalShow5.value=true
|
||||
}
|
||||
|
||||
function showK(code,name){
|
||||
data.code=code
|
||||
data.name=name
|
||||
@ -1710,6 +1718,8 @@ function delStockGroup(code,name,groupId){
|
||||
<n-button size="tiny" type="info" @click="setStock(result['股票代码'],result['股票名称'])"> 成本 </n-button>
|
||||
<n-button size="tiny" type="success" @click="showFenshi(result['股票代码'],result['股票名称'])"> 分时 </n-button>
|
||||
<n-button size="tiny" type="error" @click="showK(result['股票代码'],result['股票名称'])"> 日K </n-button>
|
||||
<n-button size="tiny" type="error" v-if="result['买一报价']>0" @click="showMoney(result['股票代码'],result['股票名称'])"> 资金 </n-button>
|
||||
|
||||
<n-button size="tiny" type="warning" @click="search(result['股票代码'],result['股票名称'])"> 详情 </n-button>
|
||||
<n-dropdown trigger="click" :options="groupList" key-field="ID" label-field="name" @select="(groupId) => AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
|
||||
<n-button type="success" size="tiny">设置分组</n-button>
|
||||
@ -1821,6 +1831,8 @@ function delStockGroup(code,name,groupId){
|
||||
<n-button size="tiny" type="info" @click="setStock(result['股票代码'],result['股票名称'])"> 成本 </n-button>
|
||||
<n-button size="tiny" type="success" @click="showFenshi(result['股票代码'],result['股票名称'],result.changePercent)"> 分时 </n-button>
|
||||
<n-button size="tiny" type="error" @click="showK(result['股票代码'],result['股票名称'])"> 日K </n-button>
|
||||
<n-button size="tiny" type="error" v-if="result['买一报价']>0" @click="showMoney(result['股票代码'],result['股票名称'])"> 资金 </n-button>
|
||||
|
||||
<n-button size="tiny" type="warning" @click="search(result['股票代码'],result['股票名称'])"> 详情 </n-button>
|
||||
<n-dropdown trigger="click" :options="groupList" key-field="ID" label-field="name" @select="(groupId) => AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
|
||||
<n-button type="success" size="tiny">设置分组</n-button>
|
||||
@ -1988,6 +2000,9 @@ function delStockGroup(code,name,groupId){
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-modal>
|
||||
<n-modal v-model:show="modalShow5" :title="data.name+'资金趋势'" style="width: 1000px" :preset="'card'" @after-enter="getMoneyTrendLine">
|
||||
<money-trend :code="data.code" :name="data.name" :days="365" :dark-theme="data.darkTheme" :chart-height="500"></money-trend>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
2
frontend/wailsjs/go/main/App.d.ts
vendored
2
frontend/wailsjs/go/main/App.d.ts
vendored
@ -49,6 +49,8 @@ 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 GetVersionInfo():Promise<models.VersionInfo>;
|
||||
|
@ -94,6 +94,10 @@ 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) {
|
||||
return window['go']['main']['App']['GetTelegraphList'](arg1);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user