|
@ -1,12 +1,12 @@ |
|
|
<template> |
|
|
<template> |
|
|
<div class="home"> |
|
|
|
|
|
|
|
|
<div class="market-temperature"> |
|
|
<div class="container"> |
|
|
<div class="container"> |
|
|
<div class="border3"> |
|
|
<div class="border3"> |
|
|
<section class="chart-section"> |
|
|
<section class="chart-section"> |
|
|
<div> |
|
|
<div> |
|
|
<div class="trapezoid"> |
|
|
<div class="trapezoid"> |
|
|
<span>NVIDIA</span> |
|
|
|
|
|
<span>NVDA</span> |
|
|
|
|
|
|
|
|
<span>{{ companyName }}</span> |
|
|
|
|
|
<span>{{ stockCode }}</span> |
|
|
</div> |
|
|
</div> |
|
|
<div ref="KlineCanvs" class="KlineClass"></div> |
|
|
<div ref="KlineCanvs" class="KlineClass"></div> |
|
|
</div> |
|
|
</div> |
|
@ -14,18 +14,9 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="border4"> |
|
|
<div class="border4"> |
|
|
<el-table |
|
|
|
|
|
:data="groupedWDRL" |
|
|
|
|
|
border |
|
|
|
|
|
:row-style="{ height: '8.6vw' }" |
|
|
|
|
|
header-cell-class-name="table_header" |
|
|
|
|
|
:cell-style="tableCellStyle" |
|
|
|
|
|
> |
|
|
|
|
|
<el-table-column |
|
|
|
|
|
v-for="(day, colIndex) in ['一', '二', '三', '四', '五', '六', '日']" |
|
|
|
|
|
:key="colIndex" |
|
|
|
|
|
:label="day" |
|
|
|
|
|
> |
|
|
|
|
|
|
|
|
<el-table :data="groupedWDRL" border :row-style="{ height: '8.6vw' }" header-cell-class-name="table_header" |
|
|
|
|
|
:cell-style="tableCellStyle"> |
|
|
|
|
|
<el-table-column v-for="(day, colIndex) in ['一', '二', '三', '四', '五', '六', '日']" :key="colIndex" :label="day"> |
|
|
<template #default="{ $index: rowIndex }"> |
|
|
<template #default="{ $index: rowIndex }"> |
|
|
<div v-if="getDayData(rowIndex, colIndex + 1)"> |
|
|
<div v-if="getDayData(rowIndex, colIndex + 1)"> |
|
|
<p class="WDRL_date"> |
|
|
<p class="WDRL_date"> |
|
@ -64,14 +55,27 @@ |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
<script setup> |
|
|
<script setup> |
|
|
import { ref, computed, onMounted, defineExpose } from 'vue' |
|
|
|
|
|
|
|
|
import { ref, computed, onMounted, defineExpose, defineProps } from 'vue' |
|
|
import * as echarts from 'echarts' |
|
|
import * as echarts from 'echarts' |
|
|
import axios from 'axios' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const props = defineProps({ |
|
|
|
|
|
companyName: { |
|
|
|
|
|
type: String, |
|
|
|
|
|
default: '' |
|
|
|
|
|
}, |
|
|
|
|
|
stockCode: { |
|
|
|
|
|
type: String, |
|
|
|
|
|
default: '' |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
const KlineCanvs = ref() |
|
|
const KlineCanvs = ref() |
|
|
const WDRL = ref([]) |
|
|
const WDRL = ref([]) |
|
|
|
|
|
const klineDataRaw = ref([]) // 用于存储 K 线图数据 |
|
|
const indexCodes = ['NDX', 'DJIA', 'SPX', 'STI', 'KLSE', 'TSX', 'N225', 'KS11', 'JKSE', '1A0001', 'HSI', 'I63', 'VNINDE'] |
|
|
const indexCodes = ['NDX', 'DJIA', 'SPX', 'STI', 'KLSE', 'TSX', 'N225', 'KS11', 'JKSE', '1A0001', 'HSI', 'I63', 'VNINDE'] |
|
|
const isIndexCode = computed(() => indexCodes.includes(localStorage.getItem('localCode'))) |
|
|
|
|
|
|
|
|
const isIndexCode = computed(() => indexCodes.includes(props.code)) |
|
|
|
|
|
|
|
|
|
|
|
// 分组 WDRL 数据 |
|
|
const groupedWDRL = computed(() => { |
|
|
const groupedWDRL = computed(() => { |
|
|
const result = [] |
|
|
const result = [] |
|
|
for (let i = 0; i < WDRL.value.length; i += 7) { |
|
|
for (let i = 0; i < WDRL.value.length; i += 7) { |
|
@ -79,6 +83,8 @@ const groupedWDRL = computed(() => { |
|
|
} |
|
|
} |
|
|
return result |
|
|
return result |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
// 获取指定日期的数据 |
|
|
function getDayData(rowIndex, dayIndex) { |
|
|
function getDayData(rowIndex, dayIndex) { |
|
|
const weekData = groupedWDRL.value[rowIndex] |
|
|
const weekData = groupedWDRL.value[rowIndex] |
|
|
if (weekData && weekData.length >= dayIndex) { |
|
|
if (weekData && weekData.length >= dayIndex) { |
|
@ -86,14 +92,20 @@ function getDayData(rowIndex, dayIndex) { |
|
|
} |
|
|
} |
|
|
return {} |
|
|
return {} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 判断是否显示分隔符 |
|
|
function shouldShowDivider(rowIndex, dayIndex) { |
|
|
function shouldShowDivider(rowIndex, dayIndex) { |
|
|
const data = getDayData(rowIndex, dayIndex) |
|
|
const data = getDayData(rowIndex, dayIndex) |
|
|
return data?.market_temperature && data?.stock_temperature |
|
|
return data?.market_temperature && data?.stock_temperature |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 判断是否都休市 |
|
|
function isBothRest(rowIndex, colIndex) { |
|
|
function isBothRest(rowIndex, colIndex) { |
|
|
const data = getDayData(rowIndex, colIndex) |
|
|
const data = getDayData(rowIndex, colIndex) |
|
|
return data && data.stock_temperature === '休市' && data.market_temperature === '休市' |
|
|
return data && data.stock_temperature === '休市' && data.market_temperature === '休市' |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 判断是否显示休市信息 |
|
|
function shouldShowRest(rowIndex, dayIndex) { |
|
|
function shouldShowRest(rowIndex, dayIndex) { |
|
|
const data = getDayData(rowIndex, dayIndex) |
|
|
const data = getDayData(rowIndex, dayIndex) |
|
|
if (data && (data.stock_temperature || data.market_temperature)) return false |
|
|
if (data && (data.stock_temperature || data.market_temperature)) return false |
|
@ -108,16 +120,22 @@ function shouldShowRest(rowIndex, dayIndex) { |
|
|
const weekday = dateObj.getDay() |
|
|
const weekday = dateObj.getDay() |
|
|
return weekday >= 1 && weekday <= 5 |
|
|
return weekday >= 1 && weekday <= 5 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 格式化月份 |
|
|
function formatMonth(dateStr) { |
|
|
function formatMonth(dateStr) { |
|
|
if (!dateStr) return '' |
|
|
if (!dateStr) return '' |
|
|
const month = dateStr.split('/')[1] |
|
|
const month = dateStr.split('/')[1] |
|
|
const map = { '01': '一月', '02': '二月', '03': '三月', '04': '四月', '05': '五月', '06': '六月', '07': '七月', '08': '八月', '09': '九月', 10: '十月', 11: '十一月', 12: '十二月' } |
|
|
const map = { '01': '一月', '02': '二月', '03': '三月', '04': '四月', '05': '五月', '06': '六月', '07': '七月', '08': '八月', '09': '九月', 10: '十月', 11: '十一月', 12: '十二月' } |
|
|
return map[month] || '' |
|
|
return map[month] || '' |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 格式化日期 |
|
|
function formatDate(dateStr) { |
|
|
function formatDate(dateStr) { |
|
|
if (!dateStr) return '' |
|
|
if (!dateStr) return '' |
|
|
return dateStr.split('/')[2] |
|
|
return dateStr.split('/')[2] |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 设置表格单元格样式 |
|
|
function tableCellStyle({ row, column, rowIndex, columnIndex }) { |
|
|
function tableCellStyle({ row, column, rowIndex, columnIndex }) { |
|
|
const data = getDayData(rowIndex, columnIndex + 1) |
|
|
const data = getDayData(rowIndex, columnIndex + 1) |
|
|
let value = isIndexCode.value ? Number(data?.market_temperature) : Number(data?.stock_temperature) |
|
|
let value = isIndexCode.value ? Number(data?.market_temperature) : Number(data?.stock_temperature) |
|
@ -129,36 +147,30 @@ function tableCellStyle({ row, column, rowIndex, columnIndex }) { |
|
|
else if (value > 0) return { backgroundColor: '#87CEEB', color: 'white' } |
|
|
else if (value > 0) return { backgroundColor: '#87CEEB', color: 'white' } |
|
|
else return { backgroundColor: '#4b759f', color: 'white' } |
|
|
else return { backgroundColor: '#4b759f', color: 'white' } |
|
|
} |
|
|
} |
|
|
const fetchData = async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
const response = await axios.post('http://39.101.133.168:8828/link/api/aiEmotion/client/getAiEmotionData', { |
|
|
|
|
|
token: '9ior41AF0xTIbIG2pRnnbZi0+fEeMx8pywnIlrmTwo5FbqJ9lWrSWOxp9MkpKiNtedtUafqvzIwpFKrwuMs', |
|
|
|
|
|
market: 'usa', |
|
|
|
|
|
code: 'TSLA', |
|
|
|
|
|
language: 'cn' |
|
|
|
|
|
}, { |
|
|
|
|
|
headers: { 'Content-Type': 'application/json' } |
|
|
|
|
|
}) |
|
|
|
|
|
if (response.data.code === 200) { |
|
|
|
|
|
WDRL.value = response.data.data.WDRL |
|
|
|
|
|
const raw = response.data.data.GSWDJ |
|
|
|
|
|
initChart(raw) |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('fetchData error:', error) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化图表 |
|
|
|
|
|
function initChart(raw, klineDataRawValue, WDRLValue) { |
|
|
|
|
|
if (!raw || !klineDataRawValue || !WDRLValue) { |
|
|
|
|
|
console.error('initChart: raw, klineDataRawValue or WDRLValue is undefined') |
|
|
|
|
|
return |
|
|
} |
|
|
} |
|
|
function initChart(raw) { |
|
|
|
|
|
|
|
|
// 处理 K 线图数据 |
|
|
|
|
|
const klineData = klineDataRawValue.map(item => { |
|
|
|
|
|
const open = item[1] |
|
|
|
|
|
const close = item[2] |
|
|
|
|
|
const low = item[3] |
|
|
|
|
|
const high = item[4] |
|
|
|
|
|
return [open, close, low, high] |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
// 温度日历 |
|
|
|
|
|
WDRL.value = WDRLValue |
|
|
|
|
|
klineDataRaw.value = klineDataRawValue |
|
|
|
|
|
|
|
|
const dateLabels = raw.map(item => item[0]) |
|
|
const dateLabels = raw.map(item => item[0]) |
|
|
const marketData = raw.map(item => Math.round(item[1])) |
|
|
const marketData = raw.map(item => Math.round(item[1])) |
|
|
const stockData = raw.map(item => Math.round(item[2])) |
|
|
const stockData = raw.map(item => Math.round(item[2])) |
|
|
const klineData = marketData.map(base => { |
|
|
|
|
|
const open = base - 3 + Math.random() * 6 |
|
|
|
|
|
const close = base - 3 + Math.random() * 6 |
|
|
|
|
|
const low = Math.min(open, close) - Math.random() * 3 |
|
|
|
|
|
const high = Math.max(open, close) + Math.random() * 3 |
|
|
|
|
|
return [open, close, low, high].map(v => Math.round(v * 10) / 10) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const chart = echarts.init(KlineCanvs.value) |
|
|
const chart = echarts.init(KlineCanvs.value) |
|
|
chart.setOption({ |
|
|
chart.setOption({ |
|
|
tooltip: {}, |
|
|
tooltip: {}, |
|
@ -195,10 +207,23 @@ function initChart(raw) { |
|
|
yAxisIndex: 1, |
|
|
yAxisIndex: 1, |
|
|
data: stockData |
|
|
data: stockData |
|
|
} |
|
|
} |
|
|
|
|
|
], |
|
|
|
|
|
// 添加 dataZoom 组件 |
|
|
|
|
|
dataZoom: [ |
|
|
|
|
|
{ |
|
|
|
|
|
type: 'slider', |
|
|
|
|
|
xAxisIndex: 0, |
|
|
|
|
|
filterMode: 'filter' |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
type: 'inside', |
|
|
|
|
|
xAxisIndex: 0, |
|
|
|
|
|
filterMode: 'filter' |
|
|
|
|
|
} |
|
|
] |
|
|
] |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
onMounted(fetchData) |
|
|
|
|
|
|
|
|
|
|
|
defineExpose({ initChart }) |
|
|
defineExpose({ initChart }) |
|
|
</script> |
|
|
</script> |
|
|
|
|
|
|
|
@ -211,6 +236,7 @@ defineExpose({ initChart }) |
|
|
padding-top: 0%; |
|
|
padding-top: 0%; |
|
|
position: relative; |
|
|
position: relative; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.month-display { |
|
|
.month-display { |
|
|
position: absolute; |
|
|
position: absolute; |
|
|
top: 0; |
|
|
top: 0; |
|
@ -218,30 +244,37 @@ defineExpose({ initChart }) |
|
|
font-size: 1vw; |
|
|
font-size: 1vw; |
|
|
color: rgb(58, 58, 58); |
|
|
color: rgb(58, 58, 58); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.WDRL_data { |
|
|
.WDRL_data { |
|
|
margin-top: 5px; |
|
|
margin-top: 5px; |
|
|
text-align: center; |
|
|
text-align: center; |
|
|
font-size: 1vw; |
|
|
font-size: 1vw; |
|
|
font-weight: bold; |
|
|
font-weight: bold; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.table_header { |
|
|
.table_header { |
|
|
color: white; |
|
|
color: white; |
|
|
background: #2a2a2a; |
|
|
background: #2a2a2a; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.KlineClass { |
|
|
.KlineClass { |
|
|
width: 100%; |
|
|
width: 100%; |
|
|
height: 400px; |
|
|
height: 400px; |
|
|
} |
|
|
} |
|
|
.home { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.market-temperature { |
|
|
min-height: 100vh; |
|
|
min-height: 100vh; |
|
|
background-color: rgb(0, 22, 65); |
|
|
background-color: rgb(0, 22, 65); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.container { |
|
|
.container { |
|
|
margin: 0 auto; |
|
|
margin: 0 auto; |
|
|
padding: 20px; |
|
|
padding: 20px; |
|
|
max-width: 80vw; |
|
|
max-width: 80vw; |
|
|
} |
|
|
} |
|
|
.border3, .border4 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.border3, |
|
|
|
|
|
.border4 { |
|
|
margin-top: 40px; |
|
|
margin-top: 40px; |
|
|
background-color: #1a1a1a; |
|
|
background-color: #1a1a1a; |
|
|
border-radius: 8px; |
|
|
border-radius: 8px; |
|
|