Browse Source

行情tab栏

zhaowenkang/feature-20251028181547-行情页面
zhaowenkang 3 weeks ago
parent
commit
2e08839371
  1. 124
      pages/marketSituation/countryMarket.vue
  2. 165
      pages/marketSituation/marketCondition.vue
  3. 25
      pages/marketSituation/marketSituation.vue
  4. 2
      vue.config.js

124
pages/marketSituation/countryMarket.vue

@ -10,14 +10,14 @@
</view> </view>
<!-- 大盘指数 --> <!-- 大盘指数 -->
<view class="section">
<view class="section" v-if="activeTabIndex === 0">
<view class="section_header"> <view class="section_header">
<text class="section_title">大盘指数</text> <text class="section_title">大盘指数</text>
<text class="section_action" @click="viewMore('indices')">查看更多 ></text> <text class="section_action" @click="viewMore('indices')">查看更多 ></text>
</view> </view>
<view class="indices_grid"> <view class="indices_grid">
<view v-for="(index, i) in countryInfo.mainIndices" :key="i" class="index_item">
<IndexCard :market="countryInfo.market" :indexName="index.name" :currentPrice="index.price" :changeAmount="index.change" :changePercent="index.changePercent" :isRising="index.isRising" />
<view v-for="(index, i) in countryInfo" :key="i" class="index_item">
<IndexCard :market="index.market" :stockName="index.name" :currentPrice="index.price" :changeAmount="index.change" :changePercent="index.changePercent" :isRising="index.isRising" />
</view> </view>
</view> </view>
@ -39,13 +39,13 @@
</view> </view>
<!-- 板块 --> <!-- 板块 -->
<view class="section">
<view class="section" v-if="activeTabIndex === 1">
<view class="section_header"> <view class="section_header">
<text class="section_title">板块</text> <text class="section_title">板块</text>
<text class="section_action" @click="viewMore('sectors')">查看更多 ></text> <text class="section_action" @click="viewMore('sectors')">查看更多 ></text>
</view> </view>
<view class="sectors_grid"> <view class="sectors_grid">
<view v-for="(sec, i) in sectors" :key="i" class="sector_item">
<view v-for="(sec, i) in countryInfo" :key="i" class="sector_item">
<view class="sector_header"> <view class="sector_header">
<text class="sector_name">{{ sec.name }}</text> <text class="sector_name">{{ sec.name }}</text>
<text :class="['sector_change', sec.isRising ? 'rising' : 'falling']"> <text :class="['sector_change', sec.isRising ? 'rising' : 'falling']">
@ -58,7 +58,7 @@
</view> </view>
<!-- 股票 --> <!-- 股票 -->
<view class="section">
<view class="section" v-if="activeTabIndex === 2">
<view class="section_header"> <view class="section_header">
<text class="section_title">股票</text> <text class="section_title">股票</text>
<text class="section_action" @click="viewMore('stocks')">查看更多 ></text> <text class="section_action" @click="viewMore('stocks')">查看更多 ></text>
@ -69,7 +69,7 @@
<text class="cell price">最新</text> <text class="cell price">最新</text>
<text class="cell change">涨幅</text> <text class="cell change">涨幅</text>
</view> </view>
<view class="table_row" v-for="(stk, i) in stocks" :key="i">
<view class="table_row" v-for="(stk, i) in countryInfo" :key="i">
<view class="cell name"> <view class="cell name">
<text class="stk_name">{{ stk.name }}</text> <text class="stk_name">{{ stk.name }}</text>
<text class="stk_code">{{ stk.code }}</text> <text class="stk_code">{{ stk.code }}</text>
@ -92,14 +92,30 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted } from "vue";
import { ref, computed, onMounted, watch } from "vue";
import IndexCard from "../../components/IndexCard.vue"; import IndexCard from "../../components/IndexCard.vue";
import { queryStockDataAPI } from "@/api/marketSituation/marketSituation";
onMounted(() => {
switchTab(0);
});
// Tab // Tab
// const marketTabs = ["", "", "", ""]; // const marketTabs = ["", "", "", ""];
const activeTabIndex = ref(0); const activeTabIndex = ref(0);
const switchTab = (i) => { const switchTab = (i) => {
activeTabIndex.value = i; activeTabIndex.value = i;
queryStockDataAPI({
parentId: props.countryId,
tradeId: activeTabIndex.value+1,
}).then((res) => {
if (res.code === 200) {
countryInfo.value = res.data.dataPage.records;
console.log(res.data)
console.log(res.data.dataPage.records)
console.log(countryInfo.value);
}
});
}; };
// //
@ -125,80 +141,31 @@ const props = defineProps({
marketTabs: { marketTabs: {
type: Array, type: Array,
}, },
});
// /
const countryInfoMap = {
2: {
//
name: "新加坡",
flag: "🇸🇬",
isMarketOpen: true,
mainIndices: [
{ name: "海峡时报指数", price: "3,234.56", change: "+12.34", changePercent: "+0.38%", isRising: true },
{ name: "FTSE ST Mid Cap", price: "1,234.56", change: "-5.67", changePercent: "-0.46%", isRising: false },
],
hotStocks: [
{ name: "星展银行", code: "D05.SI", price: "35.20", change: "+0.15", isRising: true },
{ name: "华侨银行", code: "O39.SI", price: "13.45", change: "-0.05", isRising: false },
],
},
3: {
// 西
name: "马来西亚",
flag: "🇲🇾",
isMarketOpen: false,
mainIndices: [{ name: "富时大马KLCI指数", price: "1,567.89", change: "+8.90", changePercent: "+0.57%", isRising: true }],
hotStocks: [
{ name: "马来亚银行", code: "1155.KL", price: "9.85", change: "+0.10", isRising: true },
{ name: "大众银行", code: "1295.KL", price: "4.32", change: "-0.02", isRising: false },
],
},
4: {
// 西
name: "印度尼西亚",
flag: "🇮🇩",
isMarketOpen: true,
mainIndices: [{ name: "雅加达综合指数", price: "7,234.56", change: "+45.67", changePercent: "+0.63%", isRising: true }],
hotStocks: [],
},
5: {
//
name: "美国",
flag: "🇺🇸",
isMarketOpen: false,
mainIndices: [
{ name: "道琼斯", price: "45,757.90", change: "-125.22", changePercent: "-0.27%", isRising: false },
{ name: "纳斯达克", price: "22,333.96", change: "+125.22", changePercent: "+0.47%", isRising: true },
{ name: "标普500", price: "6,606.08", change: "+125.22", changePercent: "+0.27%", isRising: true },
],
hotStocks: [
{ name: "苹果", code: "AAPL", price: "195.89", change: "+2.34", isRising: true },
{ name: "微软", code: "MSFT", price: "378.85", change: "-1.23", isRising: false },
],
tabData: {
type: Object,
default: null
}, },
};
});
// //
const countryInfo = computed(() => {
return (
countryInfoMap[props.countryId] || {
name: "未知地区",
flag: "🌍",
isMarketOpen: false,
mainIndices: [],
hotStocks: [],
const countryInfo = ref('')
//
const handleTabData = (tabData) => {
if (tabData && tabData.type === 'country' && tabData.data) {
if (tabData.data.dataPage && tabData.data.dataPage.records) {
countryInfo.value = tabData.data.dataPage.records;
console.log('countryMarket接收到数据:', countryInfo.value);
} }
);
});
}
};
//
const sectors = computed(() => {
return countryInfoMap[props.countryId]?.sectors || [];
});
const stocks = computed(() => {
return countryInfoMap[props.countryId]?.stocks || [];
});
// tabData
watch(() => props.tabData, (newTabData) => {
if (newTabData) {
handleTabData(newTabData);
}
}, { immediate: true });
// //
const viewMore = (type) => { const viewMore = (type) => {
@ -257,11 +224,8 @@ const viewMore = (type) => {
} }
.indices_grid { .indices_grid {
padding: 20rpx;
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
gap: 20rpx;
background-color: #f6f6f6;
} }
/* 情绪温度 */ /* 情绪温度 */

165
pages/marketSituation/marketCondition.vue

@ -202,6 +202,19 @@
<button @click="sendTcpMessage('init_real_time')">初始化获取行情历史数据</button> <button @click="sendTcpMessage('init_real_time')">初始化获取行情历史数据</button>
<button @click="sendTcpMessage('stop_real_time')">停止实时推送</button> <button @click="sendTcpMessage('stop_real_time')">停止实时推送</button>
</view> </view>
<view class="test" v-else-if="klineTab === 11">
<view class="button-sp-area">
<button class="mini-btn" type="default" size="mini" @click="ChangeMinutePeriod(1)">分时</button>
<button class="mini-btn" type="default" size="mini" @click="ChangeMinutePeriod(5)">5D</button>
<button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(0)">D</button>
<button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(1)">W</button>
<button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(4)">1M</button>
<button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(5)">15M</button>
</view>
<view style='background-color:#ffffff;'>
<HQChartControl ref="HQChartCtrl" DefaultChart="{Type:'KLine'}" :DefaultSymbol="Symbol"> </HQChartControl>
</view>
</view>
<view v-else class="kline-chart-container"> <view v-else class="kline-chart-container">
<text>K线图开发中...</text> <text>K线图开发中...</text>
</view> </view>
@ -236,6 +249,147 @@ import { HCharts } from "@/common/canvasMethod.js";
import tcpConnection, { TCPConnection, TCP_CONFIG } from "../../api/tcpConnection"; import tcpConnection, { TCPConnection, TCP_CONFIG } from "../../api/tcpConnection";
import { useMarketSituationStore } from "../../stores/modules/marketSituation.js"; import { useMarketSituationStore } from "../../stores/modules/marketSituation.js";
const marketSituationStore = useMarketSituationStore(); const marketSituationStore = useMarketSituationStore();
import HQChartControl from '@/uni_modules/jones-hqchart2/js_sdk/HQChartControl.vue'
//
import HQData from "@/uni_modules/jones-hqchart2/js_sdk/umychart.NetworkFilterTest.vue.js"
import { dailyDataPackets } from '@/common/dailyData.js'
//
const Symbol = ref('GBPAUD.FXCM')
const ChartWidth = ref(350)
const ChartHeight = ref(500)
const HQChartCtrl = ref(null)
//
const CreateHQChart = () => {
const chartHeight = ChartHeight.value
const hqchartCtrl = HQChartCtrl.value
if (!hqchartCtrl) return
//option
//hqchartCtrl.KLine.Option.
hqchartCtrl.NetworkFilter = NetworkFilter
hqchartCtrl.SetSize(ChartWidth.value, chartHeight)
hqchartCtrl.OnSize()
hqchartCtrl.KLine.Option.IsAutoUpdate = false
hqchartCtrl.KLine.Option.KLine.Period = 4
nextTick(() => {
hqchartCtrl.CreateHQChart()
})
}
const transformDailyDataToHQChart = (dailyDataPackets) => {
const symbol = dailyDataPackets.stock_code || Symbol.value
const rows = Array.isArray(dailyDataPackets.data) ? dailyDataPackets.data : []
// HQChart线: [Date, Open, High, Low, Close, Volume]
const data = rows.map((r, idx) => ([
parseInt(r.trade_date, 10), // Date: YYYYMMDD
Number(idx > 0 ? rows[idx - 1].bid_close : r.bid_close), // YClose:
Number(r.bid_open), // Open
Number(r.bid_high), // High
Number(r.bid_low), // Low
Number(r.bid_close), // Close
Number(r.tick_qty || 0), // Volume
Number(r.amount || 0) // Amount0
]))
return { name: symbol, symbol, ver: 2.0, data }
}
const ClearHQChart = () => {
const hqchartCtrl = HQChartCtrl.value
if (hqchartCtrl) hqchartCtrl.ClearChart()
}
const ChangeMinutePeriod = (days) => {
const hqchartCtrl = HQChartCtrl.value
if (hqchartCtrl) hqchartCtrl.ChangeMinutePeriod(days)
}
const ChangeKLinePeriod = (period) => {
const hqchartCtrl = HQChartCtrl.value
if (hqchartCtrl) hqchartCtrl.ChangeKLinePeriod(period)
}
const NetworkFilter = (data, callback) => {
console.log(`[App:NetworkFilter] Name=${data.Name} Explain=${data.Explain}`)
// HQDataCDN
data.PreventDefault = true
const reqSymbol = (data?.Request?.Data?.symbol) || Symbol.value || 'GBPAUD.FXCM'
switch (data.Name) {
// K
case 'KLineChartContainer::RequestHistoryData': {
const packet = dailyDataPackets[reqSymbol]
if (packet) {
const mock = transformDailyDataToHQChart(packet)
callback({ data: mock })
} else {
//
callback({ data: { name: reqSymbol, symbol: reqSymbol, ver: 2.0, data: [] } })
}
break
}
// K
case 'KLineChartContainer::RequestRealtimeData': {
callback({ data: { name: reqSymbol, symbol: reqSymbol, ver: 2.0, data: [] } })
break
}
// /
case 'KLineChartContainer::ReqeustHistoryMinuteData':
case 'KLineChartContainer::RequestMinuteRealtimeData':
case 'MinuteChartContainer::RequestMinuteData':
case 'MinuteChartContainer::RequestHistoryMinuteData': {
callback({ data: { name: reqSymbol, symbol: reqSymbol, ver: 2.0, data: [] } })
break
}
default: {
//
callback({ data: { name: reqSymbol, symbol: reqSymbol, ver: 2.0, data: [] } })
break
}
}
}
//
const handleShow = () => {
uni.getSystemInfo({
success: (res) => {
const width = res.windowWidth
const height = res.windowHeight
ChartWidth.value = width
ChartHeight.value = height - 65
nextTick(() => {
CreateHQChart()
})
}
})
}
//
const handleHide = () => {
ClearHQChart()
}
//
const handleUnload = () => {
ClearHQChart()
}
//
onMounted(() => {
handleShow()
})
onUnmounted(() => {
handleUnload()
})
// TCP // TCP
const tcpConnected = ref(false); const tcpConnected = ref(false);
const connectionListener = ref(null); const connectionListener = ref(null);
@ -487,10 +641,13 @@ const selectKlineTab = (tabId) => {
}); });
break; break;
case 11: case 11:
uni.showToast({
title: "暂无年K数据",
icon: "none",
duration: 2000,
// K -
nextTick(() => {
CreateHQChart();
// K
setTimeout(() => {
ChangeKLinePeriod(3);
}, 100);
}); });
break; break;
default: default:

25
pages/marketSituation/marketSituation.vue

@ -37,7 +37,7 @@
<!-- 可滚动内容区域 --> <!-- 可滚动内容区域 -->
<scroll-view class="content_scroll" scroll-y="true" :style="{ top: contentTopPosition + 'px' }"> <scroll-view class="content_scroll" scroll-y="true" :style="{ top: contentTopPosition + 'px' }">
<!-- 动态组件切换 --> <!-- 动态组件切换 -->
<component :is="currentComponent" :countryId="currentChannelId" :marketTabs="getChildMarketTabs(currentChannelId)" />
<component :is="currentComponent" :countryId="currentChannelId" :marketTabs="getChildMarketTabs(currentChannelId)" :tabData="currentTabData"/>
</scroll-view> </scroll-view>
</view> </view>
@ -61,6 +61,7 @@
</view> </view>
</view> </view>
</view> </view>
<LoginPrompt ref="loginPrompt"></LoginPrompt>
</view> </view>
</template> </template>
@ -70,12 +71,13 @@ import footerBar from "../../components/footerBar.vue";
import forexMetals from "./forexMetals.vue"; import forexMetals from "./forexMetals.vue";
import marketOverview from "./marketOverview.vue"; import marketOverview from "./marketOverview.vue";
import countryMarket from "./countryMarket.vue"; import countryMarket from "./countryMarket.vue";
import { getAllTabsAPI } from "../../api/marketSituation/marketSituation.js";
import { getAllTabsAPI, queryStockDataAPI } from "../../api/marketSituation/marketSituation.js";
const type = ref("marketSituation"); const type = ref("marketSituation");
const iSMT = ref(0); const iSMT = ref(0);
const searchValue = ref(""); const searchValue = ref("");
const contentHeight = ref(0); const contentHeight = ref(0);
const headerHeight = ref(0); // header const headerHeight = ref(0); // header
const currentTabData = ref(null);
// Tab // Tab
const channelData = ref([{ id: 1, title: "概况" }]); const channelData = ref([{ id: 1, title: "概况" }]);
@ -191,11 +193,18 @@ const navClick = (index) => {
// //
selectedCountry.value = currentItem.title; selectedCountry.value = currentItem.title;
uni.showToast({
title: `切换到: ${currentItem.title}`,
icon: "none",
});
// tab
queryStockDataAPI({
parentId: currentItem.id,
tradeId: 1,
}).then((res) => {
if (res.code == 200) {
currentTabData.value = {
type: 'country',
data: res.data
};
}
});
// tab // tab
console.log("当前选中的 tab:", currentItem); console.log("当前选中的 tab:", currentItem);
}; };
@ -586,4 +595,4 @@ watch(headerHeight, (newHeight) => {
.country_item.selected .country_text { .country_item.selected .country_text {
color: #fff; color: #fff;
} }
</style>
</style>

2
vue.config.js

@ -2,7 +2,7 @@ module.exports = {
devServer: { devServer: {
proxy: { proxy: {
'/api': { // 你的目标服务器的请求路径前缀 '/api': { // 你的目标服务器的请求路径前缀
target: 'https://hwjb.homilychart.com', // 目标服务器的地址
target: 'https://dbqb.nfdxy.net/testApi', // 目标服务器的地址
changeOrigin: true, // 是否跨域 changeOrigin: true, // 是否跨域
secure: false, // 如果是https接口,需要配置这个参数 secure: false, // 如果是https接口,需要配置这个参数
pathRewrite: { pathRewrite: {

Loading…
Cancel
Save