Compare commits
2 Commits
1179c99782
...
1a031d0be2
Author | SHA1 | Date | |
---|---|---|---|
1a031d0be2 | |||
664b66b414 |
BIN
src/assets/image/icon/echarts_markPointer.png
Normal file
BIN
src/assets/image/icon/echarts_markPointer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
@ -1,137 +1,34 @@
|
||||
<template>
|
||||
<div class="custom-echarts">
|
||||
<div id="myEcharts" class="myChart"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
//初始化eCharts
|
||||
const initEcharts = () => {
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
var myCharts = echarts.init(document.getElementById('myEcharts'))
|
||||
// 绘制图表
|
||||
myCharts.setOption({
|
||||
title: {
|
||||
text: 'FiEE, Inc. Stock Price History',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'line',
|
||||
snap: true,
|
||||
label: {
|
||||
backgroundColor: '#6a7985'
|
||||
}
|
||||
},
|
||||
formatter: function (params) {
|
||||
const p = params[0];
|
||||
return `${p.axisValue}<br/>Price: ${p.data}`;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
data: ['2013', '2015', '2017', '2019', '2021', '2023', '2025'],
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
position: 'right',
|
||||
interval: 25,
|
||||
max: 75.0,
|
||||
show: true,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '销量',
|
||||
type: 'line',
|
||||
data: [5, 20, 36, 10, 10, 20],
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
color: '#2c6288'
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#2c6288'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#F4F6F8'
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
},
|
||||
{
|
||||
type: 'slider',
|
||||
show: true,
|
||||
dataBackground: {
|
||||
lineStyle: {
|
||||
color: '#2C6288'
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 1, color: '#2c6288' },
|
||||
{ offset: 0, color: '#F4F6F8' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
selectedDataBackground: {
|
||||
lineStyle: {
|
||||
color: '#2C6288'
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 1, color: '#2c6288' },
|
||||
{ offset: 0, color: '#F4F6F8' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
fillerColor: 'rgba(44, 98, 136, 0.3)',
|
||||
realtime: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initEcharts()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.custom-echarts {
|
||||
.myChart {
|
||||
width: 1000px;
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
|
||||
import size375 from '@/components/customEcharts/size375/index.vue'
|
||||
import size768 from '@/components/customEcharts/size375/index.vue'
|
||||
import size1440 from '@/components/customEcharts/size1920/index.vue'
|
||||
import size1920 from '@/components/customEcharts/size1920/index.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const router = useRouter()
|
||||
const { width } = useWindowSize()
|
||||
const { t } = useI18n()
|
||||
|
||||
const viewComponent = computed(() => {
|
||||
const viewWidth = width.value
|
||||
if (viewWidth <= 500) {
|
||||
return size375
|
||||
} else if (viewWidth <= 960) {
|
||||
return size768
|
||||
} else if (viewWidth <= 1500) {
|
||||
return size1440
|
||||
} else if (viewWidth <= 1920 || viewWidth > 1920) {
|
||||
return size1920
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component :is="viewComponent" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
593
src/components/customEcharts/size1920/index.vue
Normal file
593
src/components/customEcharts/size1920/index.vue
Normal file
@ -0,0 +1,593 @@
|
||||
<template>
|
||||
<div class="custom-echarts">
|
||||
<div>
|
||||
<div class="echarts-header">
|
||||
<div class="echarts-header-title">
|
||||
<span>FiEE, Inc. Stock Price History</span>
|
||||
</div>
|
||||
<div class="echarts-search-area">
|
||||
<div class="echarts-search-byRange">
|
||||
<text style="font-size: 0.9rem; font-weight: 400; color: #666666;">
|
||||
Range
|
||||
</text>
|
||||
<div class="search-range-list">
|
||||
<div
|
||||
class="search-range-list-each"
|
||||
v-for="(item, index) in state.searchRange"
|
||||
:key="index"
|
||||
@click="changeSearchRange(item)"
|
||||
>
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="echarts-search-byDate">
|
||||
<n-date-picker
|
||||
v-model:value="state.selectHistoricStartDate"
|
||||
type="date"
|
||||
:is-date-disabled="disableAfterDate"
|
||||
@update:value="changeSearchRangeStartDate"
|
||||
input-readonly
|
||||
/>
|
||||
<!-- <n-icon size="16">
|
||||
<ArrowForwardOutline />
|
||||
</n-icon> -->
|
||||
<span>to</span>
|
||||
<n-date-picker
|
||||
v-model:value="state.selectHistoricEndDate"
|
||||
type="date"
|
||||
:is-date-disabled="disablePreviousDate"
|
||||
@update:value="changeSearchRangeEndDate"
|
||||
input-readonly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="myEcharts" class="myChart"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, watch, reactive } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import markPointerIcon from '@/assets/image/icon/echarts_markPointer.png'
|
||||
import axios from 'axios'
|
||||
import { NDatePicker, NIcon } from 'naive-ui'
|
||||
import { ArrowForwardOutline } from '@vicons/ionicons5'
|
||||
|
||||
const state = reactive({
|
||||
searchRange: ['1m', '3m', 'YTD', '1Y', '5Y', '10Y', 'Max'],
|
||||
selectHistoricStartDate: '2009-10-07',
|
||||
selectHistoricEndDate: new Date(),
|
||||
})
|
||||
|
||||
let myCharts = null
|
||||
let historicData = []
|
||||
let xAxisData = []
|
||||
|
||||
//初始化eCharts
|
||||
const initEcharts = (data) => {
|
||||
historicData = data
|
||||
xAxisData = data.map((item) => {
|
||||
return new Date(item.date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
})
|
||||
const yAxisData = data.map((item) => item.price)
|
||||
console.error(xAxisData, yAxisData)
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
myCharts = echarts.init(document.getElementById('myEcharts'))
|
||||
// 绘制图表
|
||||
myCharts.setOption({
|
||||
// title: {
|
||||
// text: 'FiEE, Inc. Stock Price History',
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'line',
|
||||
snap: true,
|
||||
label: {
|
||||
backgroundColor: '#6a7985',
|
||||
},
|
||||
},
|
||||
formatter: function (params) {
|
||||
const p = params[0]
|
||||
return `<span style="font-size: 1.1rem; font-weight: 600;">${p.axisValue}</span><br/><span style="font-size: 0.9rem; font-weight: 400;">Price: ${p.data}</span>`
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
data: xAxisData,
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
inverse: true,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#CCD6EB',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#323232',
|
||||
fontWeight: 'bold',
|
||||
// formatter: function (value) {
|
||||
// return value ? value.split('-')[0] : ''
|
||||
// },
|
||||
// interval: function (index, value) {
|
||||
// if (index === 0) return true;
|
||||
// const axisData = this && this.axis && this.axis.data ? this.axis.data : [];
|
||||
// if (!axisData[index - 1]) return true;
|
||||
// return value.split('-')[0] !== axisData[index - 1].split('-')[0];
|
||||
// },
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
position: 'right',
|
||||
interval: 25,
|
||||
// max: 75.0,
|
||||
show: true,
|
||||
axisLabel: {
|
||||
color: '#323232',
|
||||
fontWeight: 'bold',
|
||||
formatter: function (value) {
|
||||
return value > 0 ? value.toFixed(2) : value
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yAxisData,
|
||||
type: 'line',
|
||||
sampling: 'lttb',
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
color: '#2c6288',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#2c6288',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#F4F6F8',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
markPoint: {
|
||||
symbol: 'image://' + markPointerIcon,
|
||||
symbolSize: 24,
|
||||
data: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
},
|
||||
{
|
||||
type: 'slider',
|
||||
show: true,
|
||||
dataBackground: {
|
||||
lineStyle: {
|
||||
color: '#2C6288',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 1, color: '#2c6288' },
|
||||
{ offset: 0, color: '#F4F6F8' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
selectedDataBackground: {
|
||||
lineStyle: {
|
||||
color: '#2C6288',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 1, color: '#2c6288' },
|
||||
{ offset: 0, color: '#F4F6F8' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
fillerColor: 'rgba(44, 98, 136, 0.3)',
|
||||
realtime: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// 监听 showTip 事件,动态显示 markPoint
|
||||
myCharts.on('showTip', function (params) {
|
||||
if (params) {
|
||||
const dataIndex = params.dataIndex
|
||||
const x = myCharts.getOption().xAxis[0].data[dataIndex]
|
||||
const y = myCharts.getOption().series[0].data[dataIndex]
|
||||
myCharts.setOption({
|
||||
series: [
|
||||
{
|
||||
markPoint: {
|
||||
symbol: 'image://' + markPointerIcon,
|
||||
symbolSize: 24,
|
||||
data: [{ coord: [x, y] }],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
})
|
||||
// 鼠标移出时,清除 markPoint
|
||||
myCharts.on('globalout', function () {
|
||||
myCharts.setOption({
|
||||
series: [
|
||||
{
|
||||
markPoint: {
|
||||
symbol: 'image://' + markPointerIcon,
|
||||
symbolSize: 24,
|
||||
data: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
myCharts.on('dataZoom', function (params) {
|
||||
// 获取当前 dataZoom 范围
|
||||
const option = myCharts.getOption()
|
||||
const xAxisData = option.xAxis[0].data
|
||||
const dataZoom = option.dataZoom[1] || option.dataZoom[0]
|
||||
|
||||
// 获取 dataZoom 的 startValue 和 endValue
|
||||
let startValue = dataZoom.endValue
|
||||
let endValue = dataZoom.startValue
|
||||
|
||||
// 如果是索引,转为日期
|
||||
if (typeof startValue === 'number') {
|
||||
startValue = xAxisData[startValue]
|
||||
}
|
||||
if (typeof endValue === 'number') {
|
||||
endValue = xAxisData[endValue]
|
||||
}
|
||||
|
||||
// 更新日期选择器
|
||||
state.selectHistoricStartDate = new Date(startValue)
|
||||
state.selectHistoricEndDate = new Date(endValue)
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getHistoricalData()
|
||||
})
|
||||
|
||||
//获取历史数据
|
||||
const getHistoricalData = async () => {
|
||||
let now = new Date()
|
||||
let toDate =
|
||||
now.getFullYear() +
|
||||
'-' +
|
||||
String(now.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(now.getDate()).padStart(2, '0')
|
||||
let url =
|
||||
'https://common.szjixun.cn/api/stock/history/base/list?from=2009-10-07&to=' +
|
||||
toDate
|
||||
const res = await axios.get(url)
|
||||
if (res.status === 200) {
|
||||
if (res.data.status === 0) {
|
||||
initEcharts(res.data.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 适配倒序数据,返回大于等于目标日期的最近一天索引
|
||||
function findClosestDateIndex(data, targetDateStr) {
|
||||
let left = 0,
|
||||
right = data.length - 1
|
||||
const target = new Date(targetDateStr).getTime()
|
||||
let res = data.length - 1 // 默认返回最后一个
|
||||
while (left <= right) {
|
||||
const mid = Math.floor((left + right) / 2)
|
||||
const midTime = new Date(data[mid].date).getTime()
|
||||
if (midTime > target) {
|
||||
left = mid + 1
|
||||
} else {
|
||||
res = mid
|
||||
right = mid - 1
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 适配倒序数据,返回小于等于目标日期的最近一天索引
|
||||
function findClosestDateIndexDescLeft(data, targetDateStr) {
|
||||
let left = 0,
|
||||
right = data.length - 1
|
||||
const target = new Date(targetDateStr).getTime()
|
||||
let res = -1 // 默认返回-1(找不到)
|
||||
while (left <= right) {
|
||||
const mid = Math.floor((left + right) / 2)
|
||||
const midTime = new Date(data[mid].date).getTime()
|
||||
if (midTime < target) {
|
||||
right = mid - 1 // 向左搜索,因为我们要找的是小于等于目标日期的最近一天
|
||||
} else {
|
||||
res = mid // 记录当前找到的索引
|
||||
left = mid + 1 // 向右搜索,因为更早的日期在数组后面
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
//点击切换搜索区间
|
||||
const changeSearchRange = (range, dateTime) => {
|
||||
const now = new Date()
|
||||
let startDate = ''
|
||||
let endDate = ''
|
||||
if (range === '1m') {
|
||||
const last = new Date(now)
|
||||
last.setMonth(now.getMonth() - 1)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === '3m') {
|
||||
const last = new Date(now)
|
||||
last.setMonth(now.getMonth() - 3)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === 'YTD') {
|
||||
startDate = new Date(now.getFullYear(), 0, 1).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === '1Y') {
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 1)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === '5Y') {
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 5)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === '10Y') {
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 10)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === 'Max') {
|
||||
startDate = ''
|
||||
endDate = ''
|
||||
} else if (range === 'startDateTime') {
|
||||
startDate = dateTime
|
||||
endDate = ''
|
||||
} else if (range === 'endDateTime') {
|
||||
startDate = ''
|
||||
endDate = dateTime
|
||||
}
|
||||
if (startDate || endDate) {
|
||||
// historicData 和 xAxisData 需在 initEcharts 作用域可用
|
||||
if (
|
||||
typeof historicData !== 'undefined' &&
|
||||
typeof xAxisData !== 'undefined'
|
||||
) {
|
||||
let startValue = xAxisData[0]
|
||||
if (startDate) {
|
||||
const idx = findClosestDateIndex(historicData, startDate)
|
||||
// 用 historicData[idx].date 格式化为 xAxisData 的格式
|
||||
startValue = new Date(historicData[idx].date).toLocaleDateString(
|
||||
'en-US',
|
||||
{
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
},
|
||||
)
|
||||
}
|
||||
let endValue = endDate
|
||||
if (endDate) {
|
||||
console.warn(endDate)
|
||||
const idx = findClosestDateIndexDescLeft(historicData, endDate)
|
||||
console.warn(idx)
|
||||
// 用 historicData[idx].date 格式化为 xAxisData 的格式
|
||||
endValue = new Date(historicData[idx].date).toLocaleDateString(
|
||||
'en-US',
|
||||
{
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
},
|
||||
)
|
||||
console.warn(endValue)
|
||||
}
|
||||
|
||||
if (startDate) {
|
||||
myCharts.setOption({
|
||||
dataZoom: {
|
||||
endValue: startValue,
|
||||
},
|
||||
})
|
||||
state.selectHistoricStartDate = new Date(startValue)
|
||||
}
|
||||
if (endDate) {
|
||||
myCharts.setOption({
|
||||
dataZoom: {
|
||||
startValue: endValue,
|
||||
},
|
||||
})
|
||||
state.selectHistoricEndDate = new Date(endValue)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
myCharts.setOption({
|
||||
dataZoom: {
|
||||
startValue: '',
|
||||
endValue: '',
|
||||
},
|
||||
})
|
||||
|
||||
state.selectHistoricStartDate = new Date('2009-10-07')
|
||||
state.selectHistoricEndDate = new Date()
|
||||
}
|
||||
}
|
||||
|
||||
// 禁用2009-10-07之后的日期
|
||||
const disableAfterDate = (date) => {
|
||||
return date < new Date('2009-10-06') || date > new Date()
|
||||
}
|
||||
|
||||
// 禁用过去的日期
|
||||
const disablePreviousDate = (date) => {
|
||||
return date < new Date(state.selectHistoricStartDate) || date > new Date()
|
||||
}
|
||||
|
||||
// 切换搜索区间开始日期
|
||||
const changeSearchRangeStartDate = (date) => {
|
||||
console.error(date)
|
||||
changeSearchRange(
|
||||
'startDateTime',
|
||||
new Date(date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// 切换搜索区间结束日期
|
||||
const changeSearchRangeEndDate = (date) => {
|
||||
console.error(date)
|
||||
changeSearchRange(
|
||||
'endDateTime',
|
||||
new Date(date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
}),
|
||||
)
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.custom-echarts {
|
||||
.myChart {
|
||||
width: 100%;
|
||||
height: 25rem;
|
||||
}
|
||||
|
||||
.echarts-header {
|
||||
.echarts-header-title {
|
||||
span {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
color: #323232;
|
||||
}
|
||||
}
|
||||
.echarts-search-area {
|
||||
padding: 2rem 0 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.echarts-search-byRange {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
.search-range-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
.search-range-list-each {
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
background-color: #f3f4f6;
|
||||
cursor: pointer;
|
||||
span {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.echarts-search-byDate {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
595
src/components/customEcharts/size375/index.vue
Normal file
595
src/components/customEcharts/size375/index.vue
Normal file
@ -0,0 +1,595 @@
|
||||
<template>
|
||||
<div class="custom-echarts">
|
||||
<div>
|
||||
<div class="echarts-header">
|
||||
<div class="echarts-header-title">
|
||||
<span>FiEE, Inc. Stock Price History</span>
|
||||
</div>
|
||||
<div class="echarts-search-area">
|
||||
<div class="echarts-search-byRange">
|
||||
<text style="font-size: 0.9rem; font-weight: 400; color: #666666;">
|
||||
Range
|
||||
</text>
|
||||
<div class="search-range-list">
|
||||
<div
|
||||
class="search-range-list-each"
|
||||
v-for="(item, index) in state.searchRange"
|
||||
:key="index"
|
||||
@click="changeSearchRange(item)"
|
||||
>
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="echarts-search-byDate">
|
||||
<n-date-picker
|
||||
v-model:value="state.selectHistoricStartDate"
|
||||
type="date"
|
||||
:is-date-disabled="disableAfterDate"
|
||||
@update:value="changeSearchRangeStartDate"
|
||||
input-readonly
|
||||
/>
|
||||
<!-- <n-icon size="30">
|
||||
<ArrowForwardOutline />
|
||||
</n-icon> -->
|
||||
<span>to</span>
|
||||
<n-date-picker
|
||||
v-model:value="state.selectHistoricEndDate"
|
||||
type="date"
|
||||
:is-date-disabled="disablePreviousDate"
|
||||
@update:value="changeSearchRangeEndDate"
|
||||
input-readonly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="myEcharts" class="myChart"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, watch, reactive } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import markPointerIcon from '@/assets/image/icon/echarts_markPointer.png'
|
||||
import axios from 'axios'
|
||||
import { NDatePicker } from 'naive-ui'
|
||||
import { ArrowForwardOutline } from '@vicons/ionicons5'
|
||||
|
||||
const state = reactive({
|
||||
searchRange: ['1m', '3m', 'YTD', '1Y', '5Y', '10Y', 'Max'],
|
||||
selectHistoricStartDate: '2009-10-07',
|
||||
selectHistoricEndDate: new Date(),
|
||||
})
|
||||
|
||||
let myCharts = null
|
||||
let historicData = []
|
||||
let xAxisData = []
|
||||
|
||||
//初始化eCharts
|
||||
const initEcharts = (data) => {
|
||||
historicData = data
|
||||
xAxisData = data.map((item) => {
|
||||
return new Date(item.date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
})
|
||||
const yAxisData = data.map((item) => item.price)
|
||||
console.error(xAxisData, yAxisData)
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
myCharts = echarts.init(document.getElementById('myEcharts'))
|
||||
// 绘制图表
|
||||
myCharts.setOption({
|
||||
// title: {
|
||||
// text: 'FiEE, Inc. Stock Price History',
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'line',
|
||||
snap: true,
|
||||
label: {
|
||||
backgroundColor: '#6a7985',
|
||||
},
|
||||
},
|
||||
formatter: function (params) {
|
||||
const p = params[0]
|
||||
return `<span style="font-size: 1.1rem; font-weight: 600;">${p.axisValue}</span><br/><span style="font-size: 0.9rem; font-weight: 400;">Price: ${p.data}</span>`
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
data: xAxisData,
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
inverse: true,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#CCD6EB',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#323232',
|
||||
fontWeight: 'bold',
|
||||
// formatter: function (value) {
|
||||
// return value ? value.split('-')[0] : ''
|
||||
// },
|
||||
// interval: function (index, value) {
|
||||
// if (index === 0) return true;
|
||||
// const axisData = this && this.axis && this.axis.data ? this.axis.data : [];
|
||||
// if (!axisData[index - 1]) return true;
|
||||
// return value.split('-')[0] !== axisData[index - 1].split('-')[0];
|
||||
// },
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
position: 'right',
|
||||
interval: 25,
|
||||
// max: 75.0,
|
||||
show: true,
|
||||
axisLabel: {
|
||||
color: '#323232',
|
||||
fontWeight: 'bold',
|
||||
formatter: function (value) {
|
||||
return value > 0 ? value.toFixed(2) : value
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yAxisData,
|
||||
type: 'line',
|
||||
sampling: 'lttb',
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
color: '#2c6288',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#2c6288',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#F4F6F8',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
markPoint: {
|
||||
symbol: 'image://' + markPointerIcon,
|
||||
symbolSize: 24,
|
||||
data: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
},
|
||||
{
|
||||
type: 'slider',
|
||||
show: true,
|
||||
dataBackground: {
|
||||
lineStyle: {
|
||||
color: '#2C6288',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 1, color: '#2c6288' },
|
||||
{ offset: 0, color: '#F4F6F8' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
selectedDataBackground: {
|
||||
lineStyle: {
|
||||
color: '#2C6288',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 1, color: '#2c6288' },
|
||||
{ offset: 0, color: '#F4F6F8' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
fillerColor: 'rgba(44, 98, 136, 0.3)',
|
||||
realtime: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// 监听 showTip 事件,动态显示 markPoint
|
||||
myCharts.on('showTip', function (params) {
|
||||
if (params) {
|
||||
const dataIndex = params.dataIndex
|
||||
const x = myCharts.getOption().xAxis[0].data[dataIndex]
|
||||
const y = myCharts.getOption().series[0].data[dataIndex]
|
||||
myCharts.setOption({
|
||||
series: [
|
||||
{
|
||||
markPoint: {
|
||||
symbol: 'image://' + markPointerIcon,
|
||||
symbolSize: 24,
|
||||
data: [{ coord: [x, y] }],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
})
|
||||
// 鼠标移出时,清除 markPoint
|
||||
myCharts.on('globalout', function () {
|
||||
myCharts.setOption({
|
||||
series: [
|
||||
{
|
||||
markPoint: {
|
||||
symbol: 'image://' + markPointerIcon,
|
||||
symbolSize: 24,
|
||||
data: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
myCharts.on('dataZoom', function (params) {
|
||||
// 获取当前 dataZoom 范围
|
||||
const option = myCharts.getOption()
|
||||
const xAxisData = option.xAxis[0].data
|
||||
const dataZoom = option.dataZoom[1] || option.dataZoom[0]
|
||||
|
||||
// 获取 dataZoom 的 startValue 和 endValue
|
||||
let startValue = dataZoom.endValue
|
||||
let endValue = dataZoom.startValue
|
||||
|
||||
// 如果是索引,转为日期
|
||||
if (typeof startValue === 'number') {
|
||||
startValue = xAxisData[startValue]
|
||||
}
|
||||
if (typeof endValue === 'number') {
|
||||
endValue = xAxisData[endValue]
|
||||
}
|
||||
|
||||
// 更新日期选择器
|
||||
state.selectHistoricStartDate = new Date(startValue)
|
||||
state.selectHistoricEndDate = new Date(endValue)
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getHistoricalData()
|
||||
})
|
||||
|
||||
//获取历史数据
|
||||
const getHistoricalData = async () => {
|
||||
let now = new Date()
|
||||
let toDate =
|
||||
now.getFullYear() +
|
||||
'-' +
|
||||
String(now.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(now.getDate()).padStart(2, '0')
|
||||
let url =
|
||||
'https://common.szjixun.cn/api/stock/history/base/list?from=2009-10-07&to=' +
|
||||
toDate
|
||||
const res = await axios.get(url)
|
||||
if (res.status === 200) {
|
||||
if (res.data.status === 0) {
|
||||
initEcharts(res.data.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 适配倒序数据,返回大于等于目标日期的最近一天索引
|
||||
function findClosestDateIndex(data, targetDateStr) {
|
||||
let left = 0,
|
||||
right = data.length - 1
|
||||
const target = new Date(targetDateStr).getTime()
|
||||
let res = data.length - 1 // 默认返回最后一个
|
||||
while (left <= right) {
|
||||
const mid = Math.floor((left + right) / 2)
|
||||
const midTime = new Date(data[mid].date).getTime()
|
||||
if (midTime > target) {
|
||||
left = mid + 1
|
||||
} else {
|
||||
res = mid
|
||||
right = mid - 1
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 适配倒序数据,返回小于等于目标日期的最近一天索引
|
||||
function findClosestDateIndexDescLeft(data, targetDateStr) {
|
||||
let left = 0,
|
||||
right = data.length - 1
|
||||
const target = new Date(targetDateStr).getTime()
|
||||
let res = -1 // 默认返回-1(找不到)
|
||||
while (left <= right) {
|
||||
const mid = Math.floor((left + right) / 2)
|
||||
const midTime = new Date(data[mid].date).getTime()
|
||||
if (midTime < target) {
|
||||
right = mid - 1 // 向左搜索,因为我们要找的是小于等于目标日期的最近一天
|
||||
} else {
|
||||
res = mid // 记录当前找到的索引
|
||||
left = mid + 1 // 向右搜索,因为更早的日期在数组后面
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
//点击切换搜索区间
|
||||
const changeSearchRange = (range, dateTime) => {
|
||||
const now = new Date()
|
||||
let startDate = ''
|
||||
let endDate = ''
|
||||
if (range === '1m') {
|
||||
const last = new Date(now)
|
||||
last.setMonth(now.getMonth() - 1)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === '3m') {
|
||||
const last = new Date(now)
|
||||
last.setMonth(now.getMonth() - 3)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === 'YTD') {
|
||||
startDate = new Date(now.getFullYear(), 0, 1).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === '1Y') {
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 1)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === '5Y') {
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 5)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === '10Y') {
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 10)
|
||||
startDate = last.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
endDate = new Date(new Date()).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
} else if (range === 'Max') {
|
||||
startDate = ''
|
||||
endDate = ''
|
||||
} else if (range === 'startDateTime') {
|
||||
startDate = dateTime
|
||||
endDate = ''
|
||||
} else if (range === 'endDateTime') {
|
||||
startDate = ''
|
||||
endDate = dateTime
|
||||
}
|
||||
if (startDate || endDate) {
|
||||
// historicData 和 xAxisData 需在 initEcharts 作用域可用
|
||||
if (
|
||||
typeof historicData !== 'undefined' &&
|
||||
typeof xAxisData !== 'undefined'
|
||||
) {
|
||||
let startValue = xAxisData[0]
|
||||
if (startDate) {
|
||||
const idx = findClosestDateIndex(historicData, startDate)
|
||||
// 用 historicData[idx].date 格式化为 xAxisData 的格式
|
||||
startValue = new Date(historicData[idx].date).toLocaleDateString(
|
||||
'en-US',
|
||||
{
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
},
|
||||
)
|
||||
}
|
||||
let endValue = endDate
|
||||
if (endDate) {
|
||||
console.warn(endDate)
|
||||
const idx = findClosestDateIndexDescLeft(historicData, endDate)
|
||||
console.warn(idx)
|
||||
// 用 historicData[idx].date 格式化为 xAxisData 的格式
|
||||
endValue = new Date(historicData[idx].date).toLocaleDateString(
|
||||
'en-US',
|
||||
{
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
},
|
||||
)
|
||||
console.warn(endValue)
|
||||
}
|
||||
|
||||
if (startDate) {
|
||||
myCharts.setOption({
|
||||
dataZoom: {
|
||||
endValue: startValue,
|
||||
},
|
||||
})
|
||||
state.selectHistoricStartDate = new Date(startValue)
|
||||
}
|
||||
if (endDate) {
|
||||
myCharts.setOption({
|
||||
dataZoom: {
|
||||
startValue: endValue,
|
||||
},
|
||||
})
|
||||
state.selectHistoricEndDate = new Date(endValue)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
myCharts.setOption({
|
||||
dataZoom: {
|
||||
startValue: '',
|
||||
endValue: '',
|
||||
},
|
||||
})
|
||||
|
||||
state.selectHistoricStartDate = new Date('2009-10-07')
|
||||
state.selectHistoricEndDate = new Date()
|
||||
}
|
||||
}
|
||||
|
||||
// 禁用2009-10-07之后的日期
|
||||
const disableAfterDate = (date) => {
|
||||
return date < new Date('2009-10-06') || date > new Date()
|
||||
}
|
||||
|
||||
// 禁用过去的日期
|
||||
const disablePreviousDate = (date) => {
|
||||
return date < new Date(state.selectHistoricStartDate) || date > new Date()
|
||||
}
|
||||
|
||||
// 切换搜索区间开始日期
|
||||
const changeSearchRangeStartDate = (date) => {
|
||||
console.error(date)
|
||||
changeSearchRange(
|
||||
'startDateTime',
|
||||
new Date(date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// 切换搜索区间结束日期
|
||||
const changeSearchRangeEndDate = (date) => {
|
||||
console.error(date)
|
||||
changeSearchRange(
|
||||
'endDateTime',
|
||||
new Date(date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
}),
|
||||
)
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.custom-echarts {
|
||||
.myChart {
|
||||
width: 100%;
|
||||
height: 25rem;
|
||||
}
|
||||
|
||||
.echarts-header {
|
||||
.echarts-header-title {
|
||||
span {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
color: #323232;
|
||||
}
|
||||
}
|
||||
.echarts-search-area {
|
||||
padding: 2rem 0 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
||||
.echarts-search-byRange {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.7rem;
|
||||
.search-range-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.7rem;
|
||||
.search-range-list-each {
|
||||
padding: 0.2rem 0.3rem;
|
||||
border-radius: 5px;
|
||||
background-color: #f3f4f6;
|
||||
cursor: pointer;
|
||||
span {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.echarts-search-byDate {
|
||||
padding: 1.5rem 0 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -67,8 +67,15 @@ const getLastTradingDay = () => {
|
||||
|
||||
const formatted = ref(getLastTradingDay())
|
||||
const getStockQuate= async()=>{
|
||||
const res = await axios.get('https://saas-test.szjixun.cn/api/fiee/chart/forward/test')
|
||||
stockQuote.value=res.data
|
||||
// const res = await axios.get('https://saas-test.szjixun.cn/api/fiee/chart/forward/test')
|
||||
const res = await axios.get('https://common.szjixun.cn/api/stock/company/data')
|
||||
console.error(res)
|
||||
if(res.status === 200){
|
||||
if(res.data.status === 0){
|
||||
stockQuote.value=res.data.data
|
||||
console.error(stockQuote.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
formatted,
|
||||
|
@ -1,15 +1,18 @@
|
||||
<template>
|
||||
<div class="historic-data-container" style="margin-bottom: 40px">
|
||||
<img
|
||||
<!-- <img
|
||||
src="@/assets/image/historic-stock.png"
|
||||
alt="1"
|
||||
style="max-width: 100%; margin: 0 auto"
|
||||
/>
|
||||
/> -->
|
||||
<div class="echarts-container">
|
||||
<customEcharts></customEcharts>
|
||||
</div>
|
||||
|
||||
<div class="header mt-[20px]">
|
||||
<div class="title">Historical Data</div>
|
||||
<div class="filter-container">
|
||||
<n-dropdown
|
||||
<!-- <n-dropdown
|
||||
trigger="click"
|
||||
:options="periodOptions"
|
||||
@select="handlePeriodChange"
|
||||
@ -19,7 +22,7 @@
|
||||
{{ state.selectedPeriod }}
|
||||
<n-icon><chevron-down-outline /></n-icon>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
</n-dropdown> -->
|
||||
|
||||
<n-dropdown
|
||||
trigger="click"
|
||||
@ -92,6 +95,7 @@ import {
|
||||
ArrowUpOutline,
|
||||
} from "@vicons/ionicons5";
|
||||
import defaultTableData from "../data";
|
||||
import customEcharts from '@/components/customEcharts/index.vue'
|
||||
console.log("defaultTableData", defaultTableData);
|
||||
|
||||
// 数据筛选选项
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="historic-data-container" style="margin-bottom: 40px;">
|
||||
<img
|
||||
<!-- <img
|
||||
src="@/assets/image/historic-stock.png"
|
||||
alt="1"
|
||||
style="max-width: 100%; margin: 0 auto;"
|
||||
/>
|
||||
/> -->
|
||||
<div class="echarts-container">
|
||||
<customEcharts></customEcharts>
|
||||
</div>
|
||||
@ -12,7 +12,7 @@
|
||||
<div class="header mt-[20px]">
|
||||
<div class="title">Historical Data</div>
|
||||
<div class="filter-container">
|
||||
<n-dropdown
|
||||
<!-- <n-dropdown
|
||||
trigger="click"
|
||||
:options="periodOptions"
|
||||
@select="handlePeriodChange"
|
||||
@ -22,7 +22,7 @@
|
||||
{{ state.selectedPeriod }}
|
||||
<n-icon><chevron-down-outline /></n-icon>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
</n-dropdown> -->
|
||||
|
||||
<n-dropdown
|
||||
trigger="click"
|
||||
@ -127,7 +127,7 @@ const pageSizeOptions = [
|
||||
|
||||
const state = reactive({
|
||||
selectedPeriod: 'Daily',
|
||||
selectedDuration: '3 Months',
|
||||
selectedDuration: '6 Months',
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 50,
|
||||
@ -216,6 +216,7 @@ const handlePeriodChange = (key) => {
|
||||
|
||||
const handleDurationChange = (key) => {
|
||||
state.selectedDuration = key
|
||||
state.currentPage = 1
|
||||
getPageData()
|
||||
}
|
||||
|
||||
@ -299,42 +300,86 @@ const getPageDefaultData = async () => {
|
||||
}
|
||||
const getPageData = async () => {
|
||||
let range = ''
|
||||
let now = new Date()
|
||||
const last = new Date(now)
|
||||
last.setMonth(now.getMonth() - 6)
|
||||
let fromDate = last
|
||||
let toDate =
|
||||
now.getFullYear() +
|
||||
'-' +
|
||||
String(now.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(now.getDate()).padStart(2, '0')
|
||||
if (state.selectedDuration === '3 Months') {
|
||||
range = '3M'
|
||||
const last = new Date(now)
|
||||
last.setMonth(now.getMonth() - 3)
|
||||
fromDate = last
|
||||
} else if (state.selectedDuration === '6 Months') {
|
||||
range = '6M'
|
||||
const last = new Date(now)
|
||||
last.setMonth(now.getMonth() - 6)
|
||||
fromDate = last
|
||||
} else if (state.selectedDuration === 'Year to Date') {
|
||||
range = 'YTD'
|
||||
fromDate = new Date(now.getFullYear(), 0, 1)
|
||||
} else if (state.selectedDuration === '1 Year') {
|
||||
range = '1Y'
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 1)
|
||||
fromDate = last
|
||||
} else if (state.selectedDuration === '5 Years') {
|
||||
range = '5Y'
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 5)
|
||||
fromDate = last
|
||||
} else if (state.selectedDuration === '10 Years') {
|
||||
range = '10Y'
|
||||
const last = new Date(now)
|
||||
last.setFullYear(now.getFullYear() - 10)
|
||||
fromDate = last
|
||||
} else if (state.selectedDuration === 'Full History') {
|
||||
range = 'Max'
|
||||
fromDate = new Date('2009-10-07')
|
||||
}
|
||||
let url = `https://stockanalysis.com/api/symbol/a/OTC-MINM/history?period=${state.selectedPeriod}&range=${range}`
|
||||
let finalFromDate =
|
||||
fromDate.getFullYear() +
|
||||
'-' +
|
||||
String(fromDate.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(fromDate.getDate()).padStart(2, '0')
|
||||
// let url = `https://stockanalysis.com/api/symbol/a/OTC-MINM/history?period=${state.selectedPeriod}&range=${range}`
|
||||
let url =
|
||||
'https://common.szjixun.cn/api/stock/history/list?from=' +
|
||||
finalFromDate +
|
||||
'&to=' +
|
||||
toDate
|
||||
const res = await axios.get(url)
|
||||
if (res.data.status === 200) {
|
||||
// 转换为日期格式:"Nov 26, 2024"
|
||||
let resultData = res.data.data.map((item) => {
|
||||
return {
|
||||
date: new Date(item.t).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
}),
|
||||
open: item.o != null ? Number(item.o).toFixed(2) : '',
|
||||
high: item.h != null ? Number(item.h).toFixed(2) : '',
|
||||
low: item.l != null ? Number(item.l).toFixed(2) : '',
|
||||
close: item.c != null ? Number(item.c).toFixed(2) : '',
|
||||
adjClose: item.a != null ? Number(item.a).toFixed(2) : '',
|
||||
change: item.ch != null ? Number(item.ch).toFixed(2) + '%' : '',
|
||||
volume: item.v,
|
||||
}
|
||||
})
|
||||
state.tableData = resultData
|
||||
console.error(res)
|
||||
if (res.status === 200) {
|
||||
if (res.data.status === 0) {
|
||||
// 转换为日期格式:"Nov 26, 2024"
|
||||
let resultData = res.data.data.map((item) => {
|
||||
return {
|
||||
date: new Date(item.date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
}),
|
||||
open: item.open != null ? Number(item.open).toFixed(2) : '',
|
||||
high: item.high != null ? Number(item.high).toFixed(2) : '',
|
||||
low: item.low != null ? Number(item.low).toFixed(2) : '',
|
||||
close: item.close != null ? Number(item.close).toFixed(2) : '',
|
||||
adjClose: item.close != null ? Number(item.close).toFixed(2) : '',
|
||||
change:
|
||||
item.changePercent != null
|
||||
? Number(item.changePercent).toFixed(2) + '%'
|
||||
: '',
|
||||
volume: item.volume,
|
||||
}
|
||||
})
|
||||
state.tableData = resultData
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,15 +1,18 @@
|
||||
<template>
|
||||
<div class="historic-data-container" style="margin-bottom: 40px">
|
||||
<img
|
||||
<!-- <img
|
||||
src="@/assets/image/historic-stock-375.png"
|
||||
alt="1"
|
||||
style="max-width: 100%; margin: 0 auto"
|
||||
/>
|
||||
/> -->
|
||||
<div class="echarts-container">
|
||||
<customEcharts></customEcharts>
|
||||
</div>
|
||||
|
||||
<div class="header mt-[80px]">
|
||||
<div class="title">Historical Data</div>
|
||||
<div class="filter-container">
|
||||
<n-dropdown
|
||||
<!-- <n-dropdown
|
||||
trigger="click"
|
||||
:options="periodOptions"
|
||||
@select="handlePeriodChange"
|
||||
@ -19,7 +22,7 @@
|
||||
{{ state.selectedPeriod }}
|
||||
<n-icon><chevron-down-outline /></n-icon>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
</n-dropdown> -->
|
||||
|
||||
<n-dropdown
|
||||
trigger="click"
|
||||
@ -90,6 +93,7 @@ import {
|
||||
ArrowUpOutline,
|
||||
} from "@vicons/ionicons5";
|
||||
import defaultTableData from "../data";
|
||||
import customEcharts from '@/components/customEcharts/index.vue'
|
||||
console.log("defaultTableData", defaultTableData);
|
||||
|
||||
// 数据筛选选项
|
||||
|
@ -1,15 +1,18 @@
|
||||
<template>
|
||||
<div class="historic-data-container" style="margin-bottom: 40px">
|
||||
<img
|
||||
<!-- <img
|
||||
src="@/assets/image/historic-stock.png"
|
||||
alt="1"
|
||||
style="max-width: 100%; margin: 0 auto"
|
||||
/>
|
||||
/> -->
|
||||
<div class="echarts-container">
|
||||
<customEcharts></customEcharts>
|
||||
</div>
|
||||
|
||||
<div class="header mt-[20px]">
|
||||
<div class="title">Historical Data</div>
|
||||
<div class="filter-container">
|
||||
<n-dropdown
|
||||
<!-- <n-dropdown
|
||||
trigger="click"
|
||||
:options="periodOptions"
|
||||
@select="handlePeriodChange"
|
||||
@ -19,7 +22,7 @@
|
||||
{{ state.selectedPeriod }}
|
||||
<n-icon><chevron-down-outline /></n-icon>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
</n-dropdown> -->
|
||||
|
||||
<n-dropdown
|
||||
trigger="click"
|
||||
@ -92,6 +95,7 @@ import {
|
||||
ArrowUpOutline,
|
||||
} from "@vicons/ionicons5";
|
||||
import defaultTableData from "../data";
|
||||
import customEcharts from '@/components/customEcharts/index.vue'
|
||||
console.log("defaultTableData", defaultTableData);
|
||||
|
||||
// 数据筛选选项
|
||||
|
@ -109,7 +109,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.LAST_PRICE")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value"
|
||||
>${{ stockQuote.Open }}</span
|
||||
>${{ stockQuote.open }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -117,8 +117,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.CHANGE")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value positive"
|
||||
>{{ stockQuote.change?.[0] || "--" }}
|
||||
{{ stockQuote.change?.[1] || "--" }}</span
|
||||
>{{ stockQuote.change || "--" }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -134,7 +133,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.VOLUME")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value">{{
|
||||
stockQuote.Volume
|
||||
stockQuote.volume
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -142,7 +141,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.MARKET_CAP")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value"
|
||||
>${{ stockQuote.MarketCap }}</span
|
||||
>${{ stockQuote.marketCap }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,15 +106,14 @@
|
||||
<span class="data-label">{{
|
||||
$t("HOME.CONTAINY.STOCK_INFO.LAST_PRICE")
|
||||
}}</span>
|
||||
<span class="data-value">${{ stockQuote.Open }}</span>
|
||||
<span class="data-value">${{ stockQuote.open }}</span>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
<span class="data-label">{{
|
||||
$t("HOME.CONTAINY.STOCK_INFO.CHANGE")
|
||||
}}</span>
|
||||
<span class="data-value positive"
|
||||
>{{ stockQuote.change?.[0] || "--" }}
|
||||
{{ stockQuote.change?.[1] || "--" }}</span
|
||||
>{{ stockQuote.change || "--" }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -127,13 +126,13 @@
|
||||
<span class="data-label">{{
|
||||
$t("HOME.CONTAINY.STOCK_INFO.VOLUME")
|
||||
}}</span>
|
||||
<span class="data-value">{{ stockQuote.Volume }}</span>
|
||||
<span class="data-value">{{ stockQuote.volume }}</span>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
<span class="data-label">{{
|
||||
$t("HOME.CONTAINY.STOCK_INFO.MARKET_CAP")
|
||||
}}</span>
|
||||
<span class="data-value">${{ stockQuote.MarketCap }}</span>
|
||||
<span class="data-value">${{ stockQuote.marketCap }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -109,7 +109,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.LAST_PRICE")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value"
|
||||
>${{ stockQuote.Open }}</span
|
||||
>${{ stockQuote.open }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -117,8 +117,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.CHANGE")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value positive"
|
||||
>{{ stockQuote.change?.[0] || "--" }}
|
||||
{{ stockQuote.change?.[1] || "--" }}</span
|
||||
>{{ stockQuote.change || "--" }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -134,7 +133,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.VOLUME")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value">{{
|
||||
stockQuote.Volume
|
||||
stockQuote.volume
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -142,7 +141,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.MARKET_CAP")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value"
|
||||
>${{ stockQuote.MarketCap }}</span
|
||||
>${{ stockQuote.marketCap }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -108,7 +108,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.LAST_PRICE")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value"
|
||||
>${{ stockQuote.Open }}</span
|
||||
>${{ stockQuote.open }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -116,8 +116,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.CHANGE")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value positive"
|
||||
>{{ stockQuote.change?.[0] || "--" }}
|
||||
{{ stockQuote.change?.[1] || "--" }}</span
|
||||
>{{ stockQuote.change || "--" }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -133,7 +132,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.VOLUME")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value">{{
|
||||
stockQuote.Volume
|
||||
stockQuote.volume
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
@ -141,7 +140,7 @@
|
||||
$t("HOME.CONTAINY.STOCK_INFO.MARKET_CAP")
|
||||
}}</span>
|
||||
<span style="font-size: 18px" class="data-value"
|
||||
>${{ stockQuote.MarketCap }}</span
|
||||
>${{ stockQuote.marketCap }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -12,7 +12,7 @@ getStockQuate()
|
||||
<main ref="main" class="flex pt-80px flex-col md:flex-row justify-center items-center gap-24 rounded-3xl">
|
||||
<!-- 左侧大号价格 -->
|
||||
<section class="flex flex-col items-center justify-center glass-card p-24 rounded-2xl shadow-xl">
|
||||
<div class="text-8xl font-extrabold text-#8A5AFB animate-bg-move select-none drop-shadow-lg">${{ stockQuote.change?.[0].slice(0,4) }}</div>
|
||||
<div class="text-8xl font-extrabold text-#8A5AFB animate-bg-move select-none drop-shadow-lg">${{ stockQuote.change?.slice(0,4) }}</div>
|
||||
<div class="mt-8 text-2xl text-gray-500 font-semibold tracking-widest mb-8px">NASDAQ: <span class="text-black">MINM</span></div>
|
||||
<div class="text-gray-500">{{ formatted }}</div>
|
||||
</section>
|
||||
@ -20,29 +20,29 @@ getStockQuate()
|
||||
<section class="grid grid-cols-2 gap-12">
|
||||
<div class="info-card">
|
||||
<div class="text-base text-gray-400">Open</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.Open }}</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.open }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-base text-gray-400">Change</div>
|
||||
<div class="text-3xl font-bold"
|
||||
:class="stockQuote.change?.[1]?.startsWith('-') ? 'text-red-500' : (stockQuote.change?.[1]?.startsWith('+') ? 'text-green-500' : '')">
|
||||
{{ stockQuote.change?.join('') }}</div>
|
||||
:class="stockQuote.change?.includes('-') ? 'text-red-500' : (stockQuote.change?.includes('+') ? 'text-green-500' : '')">
|
||||
{{ stockQuote.change }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-base text-gray-400">Day's Range</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.DaysRange }}</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.daysRange }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-base text-gray-400">52-Week Range</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.Week52Range }}</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.week52Range }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-base text-gray-400">Volume</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.Volume }}</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.volume }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-base text-gray-400">Market Cap</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.MarketCap }}</div>
|
||||
<div class="text-2xl font-bold">{{ stockQuote.marketCap }}</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
@ -12,7 +12,7 @@ getStockQuate()
|
||||
>
|
||||
<!-- 左侧大号价格 -->
|
||||
<section class="flex flex-col items-center justify-center glass-card p-32 rounded-2xl shadow-xl ">
|
||||
<div class="text-9xl font-extrabold text-#8A5AFB animate-bg-move select-none drop-shadow-lg">${{ stockQuote.change?.[0].slice(0,4) }}</div>
|
||||
<div class="text-9xl font-extrabold text-#8A5AFB animate-bg-move select-none drop-shadow-lg">${{ stockQuote.change?.slice(0,4) }}</div>
|
||||
<div class="mt-10 text-3xl text-gray-500 font-semibold tracking-widest mb-10px">NASDAQ: <span class="text-black">MINM</span></div>
|
||||
<div class="text-gray-500">{{ formatted }}</div>
|
||||
</section>
|
||||
@ -20,29 +20,32 @@ getStockQuate()
|
||||
<section class="grid grid-cols-2 gap-16">
|
||||
<div class="info-card">
|
||||
<div class="text-lg text-gray-400">Open</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.Open }}</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.open }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-lg text-gray-400">Change</div>
|
||||
<div class="text-3xl font-bold"
|
||||
<!-- <div class="text-3xl font-bold"
|
||||
:class="stockQuote.change?.[1]?.startsWith('-') ? 'text-red-500' : (stockQuote.change?.[1]?.startsWith('+') ? 'text-green-500' : '')">
|
||||
{{ stockQuote.change?.join('') }}</div>
|
||||
{{ stockQuote.change?.join('') }}</div> -->
|
||||
<div class="text-3xl font-bold"
|
||||
:class="stockQuote.change?.includes('-') ? 'text-red-500' : (stockQuote.change?.includes('+') ? 'text-green-500' : '')">
|
||||
{{ stockQuote.change }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-lg text-gray-400">Day's Range</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.DaysRange }}</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.daysRange }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-lg text-gray-400">52-Week Range</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.Week52Range }}</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.week52Range }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-lg text-gray-400">Volume</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.Volume }}</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.volume }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-lg text-gray-400">Market Cap</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.MarketCap }}</div>
|
||||
<div class="text-3xl font-bold">{{ stockQuote.marketCap }}</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
@ -8,7 +8,7 @@ getStockQuate();
|
||||
<main class="min-h-60vh flex flex-col items-center justify-start px-2 py-5 pt-500px">
|
||||
<!-- 价格卡片 -->
|
||||
<section class="w-full max-w-90vw flex flex-col items-center justify-center glass-card p-4 rounded-2xl shadow mb-5">
|
||||
<div class="text-4xl font-extrabold text-#8A5AFB animate-bg-move select-none drop-shadow-lg">${{ stockQuote.change?.[0].slice(0,4) }}</div>
|
||||
<div class="text-4xl font-extrabold text-#8A5AFB animate-bg-move select-none drop-shadow-lg">${{ stockQuote.change?.slice(0,4) }}</div>
|
||||
<div class="mt-2 text-sm text-gray-500 font-semibold tracking-widest mb-0px">NASDAQ: <span class="text-black">MINM</span></div>
|
||||
<div class="text-gray-500 text-60px">{{ formatted }}</div>
|
||||
</section>
|
||||
@ -16,30 +16,30 @@ getStockQuate();
|
||||
<section class="w-full max-w-90vw grid grid-cols-2 gap-2">
|
||||
<div class="info-card">
|
||||
<div class="text-xs text-gray-400">Open</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.Open }}</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.open }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-xs text-gray-400">Change</div>
|
||||
|
||||
<div class="text-lg font-bold"
|
||||
:class="stockQuote.change?.[1]?.startsWith('-') ? 'text-red-500' : (stockQuote.change?.[1]?.startsWith('+') ? 'text-green-500' : '')">
|
||||
{{ stockQuote.change?.join('') }}</div>
|
||||
:class="stockQuote.change?.includes('-') ? 'text-red-500' : (stockQuote.change?.includes('+') ? 'text-green-500' : '')">
|
||||
{{ stockQuote.change }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-xs text-gray-400">Day's Range</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.DaysRange }}</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.daysRange }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-xs text-gray-400">52-Week Range</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.Week52Range }}</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.week52Range }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-xs text-gray-400">Volume</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.Volume }}</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.volume }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-xs text-gray-400">Market Cap</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.MarketCap }}</div>
|
||||
<div class="text-lg font-bold">{{ stockQuote.marketCap }}</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
@ -12,7 +12,7 @@ getStockQuate();
|
||||
<main class="min-h-60vh flex flex-col items-center justify-start px-4 py-6 pt-500px">
|
||||
<!-- 价格卡片 -->
|
||||
<section class="w-full max-w-80vw flex flex-col items-center justify-center glass-card p-6 rounded-2xl shadow mb-6">
|
||||
<div class="text-5xl font-extrabold text-#8A5AFB animate-bg-move select-none drop-shadow-lg">${{ stockQuote.change?.[0].slice(0,4) }}</div>
|
||||
<div class="text-5xl font-extrabold text-#8A5AFB animate-bg-move select-none drop-shadow-lg">${{ stockQuote.change?.slice(0,4) }}</div>
|
||||
<div class="mt-3 text-base text-gray-500 font-semibold tracking-widest mb-0px">NASDAQ: <span class="text-black">MINM</span></div>
|
||||
<div class="text-gray-500 text-70px">{{ formatted }}</div>
|
||||
</section>
|
||||
@ -20,29 +20,29 @@ getStockQuate();
|
||||
<section class="w-full max-w-80vw grid grid-cols-3 gap-4">
|
||||
<div class="info-card">
|
||||
<div class="text-sm text-gray-400">Open</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.Open }}</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.open }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-sm text-gray-400">Change</div>
|
||||
<div class="text-xl font-bold"
|
||||
:class="stockQuote.change?.[1]?.startsWith('-') ? 'text-red-500' : (stockQuote.change?.[1]?.startsWith('+') ? 'text-green-500' : '')">
|
||||
{{ stockQuote.change?.join('') }}</div>
|
||||
:class="stockQuote.change?.includes('-') ? 'text-red-500' : (stockQuote.change?.includes('+') ? 'text-green-500' : '')">
|
||||
{{ stockQuote.change }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-sm text-gray-400">Day's Range</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.DaysRange }}</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.daysRange }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-sm text-gray-400">52-Week Range</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.Week52Range }}</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.week52Range }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-sm text-gray-400">Volume</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.Volume }}</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.volume }}</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="text-sm text-gray-400">Market Cap</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.MarketCap }}</div>
|
||||
<div class="text-xl font-bold">{{ stockQuote.marketCap }}</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
Loading…
Reference in New Issue
Block a user