initiate
This commit is contained in:
769
src/views/target/fund/fund-detail.vue
Normal file
769
src/views/target/fund/fund-detail.vue
Normal file
@@ -0,0 +1,769 @@
|
||||
<template>
|
||||
<div class="page-div">
|
||||
<back-button />
|
||||
<div class="header">
|
||||
<div class="header-content">
|
||||
<h1 class="title">{{ fundData?.fundName }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="f-b">相关文件</div>
|
||||
<div v-if="fileList.length > 0" @click="showFileList" class="blue-color">
|
||||
查看详情
|
||||
</div>
|
||||
<div v-else class="red-color">暂无数据</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card" v-if="chartList.length > 0">
|
||||
<div class="chart-container">
|
||||
<van-loading v-show="chartList[0].loading" type="spinner" color="#1989fa" class="loading" />
|
||||
<div :id="`${chartList[0].id}`" class="chartDiv"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card" v-if="chartList.length > 1">
|
||||
<div class="chart-container">
|
||||
<van-loading v-show="chartList[1].loading" type="spinner" color="#1989fa" class="loading" />
|
||||
<div :id="`${chartList[1].id}`" class="chartDiv"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listDiv">
|
||||
<div class="data-list-container">
|
||||
<div v-if="tableList.length > 0">
|
||||
<div class="list-header">
|
||||
<div class="list-item">
|
||||
<div class="list-col date-col">日期</div>
|
||||
<div class="list-col value-col">净值</div>
|
||||
<div class="list-col value-col">月涨幅</div>
|
||||
<div class="list-col value-col">今年以来收益</div>
|
||||
</div>
|
||||
</div>
|
||||
<RecycleScroller
|
||||
class="list-body"
|
||||
:items="tableList"
|
||||
:item-size="1"
|
||||
key-field="realSysDate"
|
||||
>
|
||||
<template v-slot="{ item }">
|
||||
<div class="list-item">
|
||||
<div class="list-col date-col" :class="{ 'f-b' : item.boldFlag }">{{ item.realSysDate }}</div>
|
||||
<div class="list-col value-col">
|
||||
<div v-if="item.budget" class="tag-div"><van-tag type="success" plain>预测</van-tag></div>
|
||||
<span :class="{ 'f-b' : item.boldFlag, 'budgetHeight': item.budget }">{{ item.nav }}</span>
|
||||
</div>
|
||||
<div class="list-col value-col">
|
||||
<div v-if="item.budget" class="tag-div"><van-tag type="success" plain>预测</van-tag></div>
|
||||
<span :class="{
|
||||
'f-b' : item.boldFlag,
|
||||
'budgetHeight': item.budget,
|
||||
'red-color': item.navPercent > 0,
|
||||
'green-color' : item.navPercent < 0
|
||||
}">{{ item.navPercent || 0 }}%</span>
|
||||
</div>
|
||||
<div class="list-col value-col">
|
||||
<div v-if="item.budget" class="tag-div"><van-tag type="success" plain>预测</van-tag></div>
|
||||
<span :class="{
|
||||
'f-b' : item.boldFlag,
|
||||
'budgetHeight': item.budget,
|
||||
'red-color': item.navPercent > 0,
|
||||
'green-color' : item.navPercent < 0
|
||||
}">{{ item.yearIncomeRate || 0 }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</RecycleScroller>
|
||||
</div>
|
||||
<div class="no-data" v-else>暂无数据</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<van-popup v-model:show="showFileListPopup" position="bottom" :style="{ height: '70%' }">
|
||||
<div class="p-16">
|
||||
<div class="d-flex justify-content-between items-center mb-16">
|
||||
<div class="sub-title f-b">文件列表</div>
|
||||
<van-icon name="close" @click="showFileListPopup = false" />
|
||||
</div>
|
||||
<div class="file-list">
|
||||
<div v-for="(file, index) in fileList" :key="index" class="file-item">
|
||||
<a :href="file.fileUrl" target="_blank" class="file-link">
|
||||
<i class="iconfont" :class="`icon-${file.type}`"></i>
|
||||
<span class="file-title van-ellipsis">{{ file.fileName }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</template>
|
||||
<script setup lang='ts'>
|
||||
import BackButton from '@/components/back-button.vue'
|
||||
import { ref, onMounted, nextTick } from 'vue'
|
||||
import { RecycleScroller } from 'vue-virtual-scroller'
|
||||
|
||||
import { useRoute } from 'vue-router'
|
||||
const route = useRoute()
|
||||
import { stockAFundInfo, stockAFundFileList, stockAFundHisFundHisList, stockAFundListFund } from '@/utils/api'
|
||||
const fundData: any = ref(null)
|
||||
const fileList = ref<any[]>([])
|
||||
import { padZeroAfterDecimal } from '@/utils'
|
||||
|
||||
const init = async () => {
|
||||
try {
|
||||
const data: any = await stockAFundInfo(route.params.id + '')
|
||||
fundData.value = data.data
|
||||
const { data: file } = await stockAFundFileList({ fundId: route.params.id + '', curPage: 1, limit: 999 })
|
||||
const reg1 = /(\.xls|\.xlsx)$/
|
||||
const reg2 = /(\.pdf)$/
|
||||
const reg3 = /(\.doc|\.docx)$/
|
||||
const reg4 = /(\.ppt|\.pptx)$/
|
||||
file.list.map((ele: any) => {
|
||||
if (ele.fileUrl) {
|
||||
ele.type = 'lianjie'
|
||||
} else {
|
||||
if (ele.fileId) {
|
||||
if (reg1.test(ele.fileName)) {
|
||||
ele.type = 'excel'
|
||||
}
|
||||
if (reg2.test(ele.fileName)) {
|
||||
ele.type = 'pdf'
|
||||
}
|
||||
if (reg3.test(ele.fileName)) {
|
||||
ele.type = 'word'
|
||||
}
|
||||
if (reg4.test(ele.fileName)) {
|
||||
ele.type = 'ppt'
|
||||
}
|
||||
}
|
||||
ele.fileUrl = `${import.meta.env.VITE_BASE_URL}/file/${ele.fileId}`
|
||||
}
|
||||
})
|
||||
fileList.value = file.list
|
||||
const { data: nav } = await stockAFundHisFundHisList({ fundId: route.params.id + '' })
|
||||
nav.map((ele: any) => {
|
||||
ele.selectId = ele.id
|
||||
ele.nav = ele.nav ? padZeroAfterDecimal(ele.nav) : ''
|
||||
const month = ele.sysDate.slice(5, 7)
|
||||
ele.boldFlag = false
|
||||
if (month === '12') {
|
||||
ele.boldFlag = true
|
||||
}
|
||||
ele.budget = false
|
||||
ele.realSysDate = ele.sysDate
|
||||
ele.holdingList = []
|
||||
})
|
||||
const info2 = data.preData && data.preData.sysDate ? data.preData : null
|
||||
if (info2 && nav.length > 0) {
|
||||
let sysDate = ''
|
||||
let fundId = ''
|
||||
nav.forEach((ele: any) => {
|
||||
if (ele.holdingNum > 0) {
|
||||
sysDate = ele.sysDate
|
||||
fundId = ele.fundId
|
||||
}
|
||||
})
|
||||
const month = info2.sysDate.slice(5, 7)
|
||||
nav.push({
|
||||
sysDate: sysDate,
|
||||
fundId: fundId,
|
||||
realSysDate: info2.sysDate,
|
||||
nav: info2.price ? padZeroAfterDecimal(info2.price) : '',
|
||||
navPercent: info2.percent,
|
||||
yearIncomeRate: info2.yearIncomeRate,
|
||||
holdingNum: info2.holdingList.length,
|
||||
boldFlag: month === '12',
|
||||
budget: true,
|
||||
holdingList: info2.holdingList
|
||||
})
|
||||
}
|
||||
setLineChart(nav, data.fundConfig)
|
||||
} catch (error) {
|
||||
console.error('初始化数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
let chartList = ref<any[]>([])
|
||||
import { chartMixins } from '@/mixins/chart-mixins'
|
||||
const { charts, destroyedFlag } = chartMixins()
|
||||
import * as echarts from 'echarts'
|
||||
import { getLineSeries, getBaseOption, getXAxis, getYAxis } from '@/utils/chart'
|
||||
const tableList = ref<any[]>([])
|
||||
const setLineChart = (nav: any, fundConfig: any) => {
|
||||
if (fundData.value.configFlag === 1 && fundData.value.fundType === 'fund' && fundConfig.length > 0) {
|
||||
charts.value = [null, null]
|
||||
chartList.value = [{
|
||||
id: 'nav_chart',
|
||||
loading: true,
|
||||
}, {
|
||||
id: 'nav_list_chart',
|
||||
loading: true,
|
||||
}]
|
||||
} else {
|
||||
charts.value = [null]
|
||||
chartList.value = [{
|
||||
id: 'nav_chart',
|
||||
loading: true,
|
||||
}]
|
||||
}
|
||||
const list = nav.sort(function (a: any, b: any) {
|
||||
return new Date(a.realSysDate).getTime() - new Date(b.realSysDate).getTime()
|
||||
})
|
||||
const drawdowns: any = []
|
||||
let maxDrawdown = 0
|
||||
const tabledata: any = []
|
||||
for (let j = 0; j < list.length; j++) {
|
||||
tabledata.unshift(list[j])
|
||||
let drawdown = 0
|
||||
const nav = Number(list[j].nav)
|
||||
if (nav > maxDrawdown) {
|
||||
maxDrawdown = nav
|
||||
drawdown = 0
|
||||
} else {
|
||||
drawdown = Math.round((nav - maxDrawdown) / maxDrawdown * 10000) / 100
|
||||
}
|
||||
drawdowns.push(drawdown)
|
||||
}
|
||||
const sysDate: any = []
|
||||
const seriesData: any = []
|
||||
const drawdownsData: any = []
|
||||
list.forEach((ele: any, index: number) => {
|
||||
sysDate.push(ele.realSysDate)
|
||||
seriesData.push({ value: ele.nav, drawdown: drawdowns[index] })
|
||||
drawdownsData.push({ value: drawdowns[index], nav: ele.nav, sysDate: ele.realSysDate })
|
||||
})
|
||||
const series = [
|
||||
getLineSeries({ data: seriesData, name: '历史净值', areaStyle: { color: '#FAE5E3' }, color: '#FF3732' }),
|
||||
getLineSeries({ data: drawdownsData, yAxisIndex: 1, xAxisIndex: 1, name: '回撤走势', areaStyle: { color: '#FAE5E3' }, color: '#FF3732' })
|
||||
]
|
||||
if (drawdownsData.length > 3) {
|
||||
const minTime = new Date(drawdownsData[0].sysDate).getTime()
|
||||
const maxTime = new Date(drawdownsData[drawdownsData.length - 1].sysDate).getTime()
|
||||
const range = Math.round((maxTime - minTime) / 6)
|
||||
const min1 = getPoint(drawdownsData)
|
||||
const left = []
|
||||
const right = []
|
||||
for (let i = 0; i < drawdownsData.length; i++) {
|
||||
if (new Date(min1.sysDate).getTime() - new Date(drawdownsData[i].sysDate).getTime() - range > 0) {
|
||||
left.push(drawdownsData[i])
|
||||
}
|
||||
if (new Date(drawdownsData[i].sysDate).getTime() - range - new Date(min1.sysDate).getTime() > 0) {
|
||||
right.push(drawdownsData[i])
|
||||
}
|
||||
}
|
||||
let min2: any = {}
|
||||
let min3: any = {}
|
||||
if (left.length > 0 && right.length > 0) {
|
||||
min2 = getPoint(left)
|
||||
min3 = getPoint(right)
|
||||
} else if (left.length > 0 && right.length === 0) {
|
||||
min2 = getPoint(left)
|
||||
const left1 = []
|
||||
const right1 = []
|
||||
for (let i = 0; i < left.length; i++) {
|
||||
if (new Date(min2.sysDate).getTime() - new Date(left[i].sysDate).getTime() - range > 0) {
|
||||
left1.push(left[i])
|
||||
}
|
||||
if (new Date(left[i].sysDate).getTime() - range - new Date(min2.sysDate).getTime() > 0) {
|
||||
right1.push(left[i])
|
||||
}
|
||||
}
|
||||
min3 = getPoint([...left1, ...right1])
|
||||
} else if (left.length === 0 && right.length > 0) {
|
||||
min2 = getPoint(right)
|
||||
const left2 = []
|
||||
const right2 = []
|
||||
for (let i = 0; i < right.length; i++) {
|
||||
if (new Date(min2.sysDate).getTime() - new Date(right[i].sysDate).getTime() - range > 0) {
|
||||
left2.push(right[i])
|
||||
}
|
||||
if (new Date(right[i].sysDate).getTime() - range - new Date(min2.sysDate).getTime() > 0) {
|
||||
right2.push(right[i])
|
||||
}
|
||||
}
|
||||
min3 = getPoint([...left2, ...right2])
|
||||
}
|
||||
series[1].markPoint = {
|
||||
data: [{
|
||||
name: 1,
|
||||
value: min1.num,
|
||||
coord: [min1.sysDate, min1.num],
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)'
|
||||
},
|
||||
label: {
|
||||
position: 'bottom',
|
||||
color: '#f58220'
|
||||
}
|
||||
}, {
|
||||
name: 2,
|
||||
value: min2.num,
|
||||
coord: [min2.sysDate, min2.num],
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)'
|
||||
},
|
||||
label: {
|
||||
position: 'bottom',
|
||||
color: '#0000ff'
|
||||
}
|
||||
}, {
|
||||
name: 3,
|
||||
value: min3.num,
|
||||
coord: [min3.sysDate, min3.num],
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)'
|
||||
},
|
||||
label: {
|
||||
position: 'bottom',
|
||||
color: '#65c294'
|
||||
}
|
||||
}]
|
||||
}
|
||||
} else {
|
||||
series[1].markPoint = {
|
||||
data: drawdownsData.map((ele: any, i: number) => ({
|
||||
name: `${i + 1}`,
|
||||
value: ele.value,
|
||||
coord: [sysDate[i], ele.value],
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)'
|
||||
},
|
||||
label: {
|
||||
position: 'bottom',
|
||||
color: i === 0 ? '#f58220' : i === 1 ? '#0000ff' : '#65c294'
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
const option = getBaseOption({
|
||||
yAxis: [getYAxis({ }), getYAxis({ gridIndex: 1, axisLabel: '{value}%' })],
|
||||
xAxis: [getXAxis({ data: sysDate }), getXAxis({ data: sysDate, gridIndex: 1, showFlag: false })],
|
||||
series: series,
|
||||
title: [{ text: '历史净值' }, { text: '回撤情况', top: '54%' }],
|
||||
grid: [{ bottom: '54%', left: '40px', right: '40px', top: '40px' }, { top: '66%', bottom: '20px', left: '40px', right: '40px' }],
|
||||
formatter: function (data: any) {
|
||||
let res = `${data[0].name}<br/>`
|
||||
data.forEach((ele: any) => {
|
||||
res += `历史净值:${ele.seriesName === '历史净值' ? ele.data.value : ele.data.nav}<br/>`
|
||||
res += `回撤:${ele.seriesName === '历史净值' ? ele.data.drawdown : ele.data.value}%<br/>`
|
||||
})
|
||||
return res
|
||||
}
|
||||
})
|
||||
nextTick(() =>{
|
||||
if (!destroyedFlag.value && document.getElementById(chartList.value[0].id)) {
|
||||
const chart = echarts.init(document.getElementById(chartList.value[0].id))
|
||||
chart.setOption(option)
|
||||
charts.value[0] = chart
|
||||
chartList.value[0].loading = false
|
||||
}
|
||||
if (fundData.value.configFlag === 1 && fundData.value.fundType === 'fund' && fundConfig.length > 0) {
|
||||
getFundList(fundConfig)
|
||||
tableList.value = tabledata
|
||||
} else {
|
||||
tableList.value = tabledata
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getPoint = (drawdownsData: any) => {
|
||||
const minValue = {
|
||||
num: drawdownsData[0].value,
|
||||
sysDate: drawdownsData[0].sysDate
|
||||
}
|
||||
for (let i = 1; i < drawdownsData.length; i++) {
|
||||
if (drawdownsData[i].value < minValue.num) {
|
||||
minValue.num = drawdownsData[i].value
|
||||
minValue.sysDate = drawdownsData[i].sysDate
|
||||
}
|
||||
}
|
||||
return minValue
|
||||
}
|
||||
|
||||
const getFundList = async(fundConfig: any) => {
|
||||
const { data } = await stockAFundListFund()
|
||||
const multipleSelection: any = []
|
||||
data.fundList.forEach((ele: any) => {
|
||||
const fund = fundConfig.find((res: any) => {
|
||||
return ele.fundId === res.configFundId
|
||||
})
|
||||
if (fund && fund.sysDate && fund.weight) {
|
||||
multipleSelection.push({
|
||||
weight: fund.weight,
|
||||
sysDate: fund.sysDate,
|
||||
stockPriceList: ele.stockPriceList,
|
||||
fundName: ele.fundName,
|
||||
fundId: ele.fundId
|
||||
})
|
||||
}
|
||||
})
|
||||
getChart(multipleSelection)
|
||||
}
|
||||
|
||||
const getChart = (multipleSelection: any) => {
|
||||
const colorPalette = generateColors(multipleSelection.length + 1)
|
||||
const legend: any = []
|
||||
const seriesList: any = []
|
||||
const sysDate: any = []
|
||||
multipleSelection.sort((a: any, b: any) => new Date(a.sysDate).getTime() - new Date(b.sysDate).getTime())
|
||||
multipleSelection.forEach((ele: any, index: number) => {
|
||||
legend.push(ele.fundName)
|
||||
seriesList.push(getLineSeries({ name: ele.fundName, color: colorPalette[index] }))
|
||||
seriesList.push(getLineSeries({ name: ele.fundName, yAxisIndex: 1, xAxisIndex: 1, color: colorPalette[index] }))
|
||||
const priceIndex = ele.stockPriceList.findIndex((res: any) => {
|
||||
return new Date(res.sysDate).getTime() >= new Date(ele.sysDate).getTime()
|
||||
})
|
||||
const stockPriceList = ele.stockPriceList.slice(priceIndex)
|
||||
const per = stockPriceList.length > 0 ? stockPriceList[0].nav : 1
|
||||
let maxDrawdown = 0
|
||||
stockPriceList.forEach((res: any) => {
|
||||
if (!sysDate.includes(res.sysDate)) {
|
||||
sysDate.push(res.sysDate)
|
||||
}
|
||||
const nav = res.nav ? Math.round(res.nav / per * 10000) / 10000 : 0
|
||||
let drawdown = 0
|
||||
if (nav > maxDrawdown) {
|
||||
maxDrawdown = nav
|
||||
drawdown = 0
|
||||
} else {
|
||||
drawdown = Math.round((nav - maxDrawdown) / maxDrawdown * 10000) / 100
|
||||
}
|
||||
seriesList[index * 2].data.push([res.sysDate, res.nav, drawdown])
|
||||
seriesList[index * 2 + 1].data.push([res.sysDate, drawdown, res.nav])
|
||||
})
|
||||
})
|
||||
sysDate.sort((a: any, b: any) => new Date(a).getTime() - new Date(b).getTime())
|
||||
const moneyList: any = []
|
||||
const navList: any = []
|
||||
sysDate.forEach((ele: any) => {
|
||||
const countList: any = []
|
||||
seriesList.forEach((res: any, index: number) => {
|
||||
if (index % 2 === 0) {
|
||||
if (new Date(multipleSelection[index / 2].sysDate).getTime() <= new Date(ele).getTime()) {
|
||||
const navItem = res.data.find((item: any) => {
|
||||
return item[0] === ele
|
||||
})
|
||||
if (navItem) {
|
||||
countList.push({
|
||||
weight: Number(multipleSelection[index / 2].weight),
|
||||
nav: navItem[1],
|
||||
marketValue: 0,
|
||||
fundId: multipleSelection[index / 2].fundId
|
||||
})
|
||||
} else {
|
||||
countList.push({
|
||||
weight: Number(multipleSelection[index / 2].weight),
|
||||
nav: 0,
|
||||
marketValue: 0,
|
||||
fundId: multipleSelection[index / 2].fundId
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
let weights = 0
|
||||
countList.forEach((ele: any) => {
|
||||
weights += ele.weight
|
||||
})
|
||||
let marketValue = 0
|
||||
if (moneyList.length === 0) {
|
||||
countList.map((res: any) => {
|
||||
res.marketValue = Math.round(Number(fundData.value.initAmount) * res.weight / weights * 100) / 100
|
||||
marketValue += res.marketValue
|
||||
})
|
||||
} else {
|
||||
if (countList.length > moneyList[moneyList.length - 1].length) {
|
||||
countList.forEach((res: any, index: number) => {
|
||||
if (index < moneyList[moneyList.length - 1].length) {
|
||||
if (res.nav) {
|
||||
marketValue += Math.round(moneyList[moneyList.length - 1][index].marketValue / moneyList[moneyList.length - 1][index].nav * res.nav * 100) / 100
|
||||
} else {
|
||||
marketValue += moneyList[moneyList.length - 1][index].marketValue
|
||||
}
|
||||
}
|
||||
})
|
||||
countList.map((res: any, index: number) => {
|
||||
if (index >= moneyList[moneyList.length - 1].length) {
|
||||
res.marketValue = Math.round(marketValue * res.weight / weights * 100) / 100
|
||||
} else {
|
||||
res.marketValue = Math.round(marketValue * res.weight / weights * 100) / 100
|
||||
}
|
||||
})
|
||||
} else {
|
||||
countList.map((res: any, index: number) => {
|
||||
if (res.nav) {
|
||||
res.marketValue = Math.round(moneyList[moneyList.length - 1][index].marketValue / moneyList[moneyList.length - 1][index].nav * res.nav * 100) / 100
|
||||
} else {
|
||||
res.marketValue = moneyList[moneyList.length - 1][index].marketValue
|
||||
}
|
||||
marketValue += res.marketValue
|
||||
})
|
||||
}
|
||||
}
|
||||
moneyList.push(countList)
|
||||
navList.push({ sysDate: sysDate[0], nav: Math.round(marketValue / Number(fundData.value.initAmount) * 10000) / 10000 })
|
||||
})
|
||||
legend.push('本基金')
|
||||
seriesList.push(getLineSeries({ name: '本基金', color: colorPalette[colorPalette.length - 1] }))
|
||||
seriesList.push(getLineSeries({ name: '本基金', yAxisIndex: 1, xAxisIndex: 1, color: colorPalette[colorPalette.length - 1] }))
|
||||
let maxDrawdown = 0
|
||||
navList.forEach((ele: any) => {
|
||||
let drawdown = 0
|
||||
const nav = Number(ele.nav)
|
||||
if (nav > maxDrawdown) {
|
||||
maxDrawdown = nav
|
||||
drawdown = 0
|
||||
} else {
|
||||
drawdown = Math.round((nav - maxDrawdown) / maxDrawdown * 10000) / 100
|
||||
}
|
||||
seriesList[seriesList.length - 2].data.push([ele.sysDate, nav, drawdown])
|
||||
seriesList[seriesList.length - 1].data.push([ele.sysDate, drawdown, nav])
|
||||
})
|
||||
const option = getBaseOption({
|
||||
yAxis: [getYAxis({ }), getYAxis({ gridIndex: 1, axisLabel: '{value}%' })],
|
||||
xAxis: [getXAxis({ data: sysDate }), getXAxis({ data: sysDate, gridIndex: 1, showFlag: false })],
|
||||
series: seriesList,
|
||||
formatter: function (data: any) {
|
||||
let res = `${data[0].value[0]}<br/>`
|
||||
data.forEach((ele: any) => {
|
||||
res += `<span style="color: ${ele.color}">${ele.seriesName}:历史净值${ele.axisIndex % 2 === 0 ? ele.value[1] : ele.value[2]},回撤${ele.axisIndex % 2 === 0 ? ele.value[2] : ele.value[1]}%</span><br/>`
|
||||
})
|
||||
return res
|
||||
},
|
||||
legend: { data: legend, top: '40px' },
|
||||
title: [{ text: '历史净值' }, { text: '回撤情况', top: '54%' }],
|
||||
grid: [{ bottom: '54%', left: '40px', right: '40px', top: '90px' }, { top: '66%', bottom: '20px', left: '40px', right: '40px' }],
|
||||
color: colorPalette
|
||||
})
|
||||
if (!destroyedFlag.value && document.getElementById(chartList.value[1].id)) {
|
||||
const chart = echarts.init(document.getElementById(chartList.value[1].id))
|
||||
chart.setOption(option)
|
||||
charts.value[1] = chart
|
||||
chartList.value[1].loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const generateColors = (numLines: number) => {
|
||||
const colors = []
|
||||
const m = numLines - 1
|
||||
if (m > 0) {
|
||||
const startHue = 30
|
||||
const endHue = 330
|
||||
const step = m === 1 ? 0 : (endHue - startHue) / (m - 1)
|
||||
for (let i = 0; i < m; i++) {
|
||||
const h = startHue + (step * i)
|
||||
const s = 70
|
||||
const l = 70
|
||||
colors.push(hslToHex(h, s, l))
|
||||
}
|
||||
}
|
||||
colors.push('#ff0000')
|
||||
return colors
|
||||
}
|
||||
|
||||
const hslToHex = (h : number, s: number, l: number) => {
|
||||
h /= 360
|
||||
s /= 100
|
||||
l /= 100
|
||||
const c = (1 - Math.abs(2 * l - 1)) * s
|
||||
const x = c * (1 - Math.abs((h * 6) % 2 - 1))
|
||||
const m = l - c / 2
|
||||
let r, g, b
|
||||
const i = Math.floor(h * 6)
|
||||
switch (i) {
|
||||
case 0: r = c; g = x; b = 0; break
|
||||
case 1: r = x; g = c; b = 0; break
|
||||
case 2: r = 0; g = c; b = x; break
|
||||
case 3: r = 0; g = x; b = c; break
|
||||
case 4: r = x; g = 0; b = c; break
|
||||
default: r = c; g = 0; b = x; break
|
||||
}
|
||||
r = Math.round((r + m) * 255)
|
||||
g = Math.round((g + m) * 255)
|
||||
b = Math.round((b + m) * 255)
|
||||
return '#' + [r, g, b].map(v => v.toString(16).padStart(2, '0')).join('')
|
||||
}
|
||||
|
||||
const showFileListPopup = ref(false)
|
||||
const showFileList = () => {
|
||||
showFileListPopup.value = true
|
||||
}
|
||||
onMounted (() =>{
|
||||
init()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
|
||||
.page-div {
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
scroll-behavior: smooth;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding-top: 86px;
|
||||
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
left: calc(50vw - 496px);
|
||||
right: calc(50vw - 496px);
|
||||
}
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
height: 40vh;
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
height: 60vh;
|
||||
}
|
||||
}
|
||||
|
||||
.listDiv {
|
||||
padding: 0 16px;
|
||||
|
||||
.data-list-container {
|
||||
width: 100%;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
background-color: #fff;
|
||||
max-height: none !important;
|
||||
overflow: visible !important;
|
||||
height: auto !important;
|
||||
-webkit-overflow-scrolling: auto;
|
||||
|
||||
.list-header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #e8ebed;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #e8ebed;
|
||||
height: 48px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.list-body {
|
||||
overflow: visible !important;
|
||||
max-height: none !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.list-col {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
padding: 0 8px;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
color: #333;
|
||||
|
||||
&.date-col {
|
||||
flex: 0 0 30%;
|
||||
text-align: left;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.budgetHeight {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.tag-div {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
padding: 30px 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
|
||||
.listDiv {
|
||||
padding: 0 12px;
|
||||
|
||||
.data-list-container {
|
||||
.list-item {
|
||||
padding: 10px 12px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.list-col {
|
||||
font-size: 12px;
|
||||
padding: 0 4px;
|
||||
color: #333;
|
||||
|
||||
&.date-col {
|
||||
flex: 0 0 25%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.file-list {
|
||||
max-height: calc(100% - 60px);
|
||||
overflow-y: auto;
|
||||
padding-bottom: 20px;
|
||||
|
||||
.file-item {
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.file-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.file-title {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
padding: 0 16px 20px;
|
||||
|
||||
.file-item {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.file-link {
|
||||
i {
|
||||
font-size: 24px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.file-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user