Files
intc-vue3/src/views/invest/stocksAnalysis/index.vue
2024-10-22 11:22:27 +08:00

522 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<div class="search-con">
<div class="title">查询条件</div>
<el-form :model="queryParams" ref="queryRef" :inline="true" :rules="rules" label-width="100px">
<el-form-item label="股票账户" prop="futureStocksId">
<el-select v-model="queryParams.id" placeholder="请选择股票账户" clearable>
<el-option v-for="futureStocks in futureStocksList" :key="futureStocks.id" :label="futureStocks.nameCode" :value="futureStocks.id" />
</el-select>
</el-form-item>
<el-form-item label="" prop="type">
<el-select v-model="queryParams.type" @change="handleTimeChange" placeholder="请选择日期">
<el-option v-for="item in dates" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="" prop="time" v-if="queryParams.type === 1">
<el-date-picker
v-model="queryParams.time"
type="daterange"
range-separator="~"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD"
:disabled-date="disabledDateFun"
@calendar-change="calendarChange"
/>
</el-form-item>
<el-form-item label="" prop="time" v-if="queryParams.type === 2">
<el-date-picker
v-model="queryParams.time"
type="monthrange"
range-separator="~"
format="YYYY-MM"
start-placeholder="开始时间"
end-placeholder="结束时间"
:disabled-date="disabledDateFun"
@calendar-change="calendarChange"
/>
</el-form-item>
<el-form-item label="" prop="time" v-if="queryParams.type === 3">
<yearPicker
v-model="queryParams.time"
ref="statisticPicker"
labelText="选择年份"
:initYear="dateValue"
:showYear="showYearValue"
:maxLength="10"
sp="~"
@updateTimeRange="updateStatisticYear"
/>
</el-form-item>
</el-form>
<div class="search-btn-con">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button type="info" icon="Refresh" @click="resetQuery">重置</el-button>
</div>
</div>
<div class="main-con" style="height: calc(100% - 2.05rem)">
<div class="summary-con">
<div class="right-con">
<div class="img">
<img src="@/assets/images/accumulate.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">累计收益</div>
<div>
<span class="num">{{ futuresStock.accumulateIncome }}</span> <span class="unit"></span>
</div>
</div>
</div>
<div class="center-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">平均收益</div>
<div>
<span class="num">{{ futuresStock.averageIncome }}</span> <span class="unit"></span>
</div>
</div>
</div>
<div class="center-con">
<div class="img">
<img src="@/assets/images/chart-pie.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">最大收益</div>
<div>
<span class="num">{{ futuresStock.maxRevenue }}</span> <span class="unit"></span>
</div>
</div>
</div>
<div class="center-con">
<div class="img">
<img src="@/assets/images/accumulate.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">最大亏损</div>
<div>
<span class="num">{{ futuresStock.maxLoss }}</span> <span class="unit"></span>
</div>
</div>
</div>
</div>
<div class="title-con">
<div class="title">收益统计</div>
<div class="operate-btn-con">
<el-radio-group v-model="radioVal" @change="handleRadioChange">
<el-radio-button label="柱状图" />
<el-radio-button label="折线图" />
<el-radio-button label="表格" />
</el-radio-group>
</div>
</div>
<div class="content-con">
<div v-show="radioVal === '柱状图'" class="chart" id="chartBar" style="height: calc(100% - 170px)"></div>
<div v-show="radioVal === '折线图'" class="chart" id="chartLine" style="height: calc(100% - 170px)"></div>
<el-table v-show="radioVal === '表格'" v-loading="loading" :data="futuresStock.tableFuturesStocksList" height="calc(100% - 170px)">
<el-table-column label="序号" width="50" type="index" align="center">
<template #default="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="统计日期" align="center" prop="time" />
<el-table-column label="收益" align="center" prop="value" />
<el-table-column prop="detail" label="收益明细" width="700" v-if="queryParams.type === 2">
<template #default="scope">
<span v-html="formatMultiLineData(scope.row.detail)"></span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script setup name="CreditAnalysis">
import dayjs from 'dayjs'
import * as echarts from 'echarts'
import { ElMessage } from 'element-plus'
import yearPicker from '@/components/YearPicker/index.vue'
import { getFuturesStocksAnalysis } from '@/api/invest/statisticAnalysis'
import { listFutureStocks } from '@/api/invest/futureStocks'
const { proxy } = getCurrentInstance()
const dateValue = ref({ startYear: 2000, endYear: new Date().getFullYear() })
const showYearValue = ref({ startShowYear: '', endShowYear: '' })
const updateStatisticYear = (startYear, endYear) => {
queryParams.value.time = [new Date(startYear, 0, 1), new Date(endYear, 0, 1)]
if (endYear - startYear > 10) {
ElMessage.warning('时间跨度不能大于10年默认选择开始日期的5年')
queryParams.value.time = [new Date(startYear, 0, 1), new Date(startYear + 5, 0, 1)]
}
}
const dates = [
{ value: 2, label: '月' },
{ value: 3, label: '年' }
]
const loading = ref(true)
const total = ref(0)
const radioVal = ref('柱状图')
const dateKey = ref('月')
const futureStocksList = ref([])
const dateValidate = (rules, value, callback) => {
const dateType = rules.dateType || 'days'
const num = rules.num || 31
const dateString = rules.dateString || '天'
const message = rules.message || `时间跨度不能超过${num}${dateString}`
if (value && value.length === 2) {
const start = value[0]
const end = value[1]
if (dayjs(end).diff(dayjs(start), dateType) > num) {
queryParams.value.time = [start, dayjs(start).add(59, 'months')]
ElMessage.warning(message)
}
}
}
const data = reactive({
queryParams: {
type: 2,
time: null,
dataType: '2',
id: null
},
queryFutureStocksListParams: {
pageNum: 1,
type: '2',
pageSize: 1000
},
rules: {
time: [{ validator: dateValidate, dateType: 'months', num: 59, dateRange: '月', message: '时间跨度不能大于60个月默认选择开始日期的24个月' }]
}
})
const { queryParams, queryFutureStocksListParams, rules } = toRefs(data)
const today = new Date()
const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2)
const start = dayjs(end).add(-59, 'months')
queryParams.value.time = [start, end]
/** 查询期货股票卡管理列表 */
function getFutureStocksList() {
listFutureStocks(queryFutureStocksListParams.value).then((response) => {
futureStocksList.value = response.rows
})
}
function formatMultiLineData(data) {
if (data != null) {
return data.replace(/<br\/>/g, '<br/>')
}
}
const handleTimeChange = (type) => {
queryParams.value.time = null
if (type === 2) {
const today = new Date()
const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2)
const start = dayjs(end).add(-59, 'months')
queryParams.value.time = [start, end]
} else if (type === 3) {
const today = new Date()
const endYear = today.getFullYear()
queryParams.value.time = [new Date(endYear - 10, 0, 1), new Date(endYear, 0, 1)]
showYearValue.value = { startShowYear: endYear - 10, endShowYear: endYear }
}
getList()
}
const disabledDateFun = (time) => {
const arr = [0, 30, 365, 365 * 5]
const days = arr[queryParams.value.type]
if (firstChooseDate.value) {
const one = days * 24 * 3600 * 1000
const minTime = firstChooseDate.value - one
const maxTime = firstChooseDate.value + one
const startTime = minTime
const endTime = maxTime > Date.now() - 8.64e7 ? Date.now() - 8.64e7 : maxTime
return time.getTime() > endTime || time.getTime() < startTime
} else {
return time.getTime() > Date.now() - 8.64e7
}
}
const firstChooseDate = ref('')
const calendarChange = (val) => {
firstChooseDate.value = val[0].getTime()
if (val[1]) firstChooseDate.value = ''
}
const futuresStock = ref({
maxRevenue: '',
maxLoss: '',
averageIncome: '',
accumulateIncome: '',
futuresStocksList: []
})
const chartData = ref({
name: [],
value1: []
})
function getList() {
loading.value = true
chartData.value = { name: [], value1: [] }
const { type, time, dataType, id } = queryParams.value
let formatValue = 'YYYY-MM-DD'
if (type === 1) {
formatValue = 'YYYY-MM-DD'
} else if (type === 2) {
formatValue = 'YYYY-MM'
} else {
formatValue = 'YYYY'
}
const params = {
type,
startTime: time && time.length > 0 ? dayjs(time[0]).format(formatValue) : '',
endTime: time && time.length > 0 ? dayjs(time[1]).format(formatValue) : '',
id,
dataType
}
getFuturesStocksAnalysis(params).then((response) => {
loading.value = false
futuresStock.value = { ...response.data }
futuresStock.value.futuresStocksList.map((item) => {
return {
name: item.time,
value: item.value
}
})
response.data.futuresStocksList.map((item) => {
chartData.value.name.push(item.time)
chartData.value.value1.push(item.value)
})
handleRadioChange(currentType.value)
})
}
function handleQuery() {
getList()
}
function resetQuery() {
proxy.resetForm('queryRef')
queryParams.value.id = null
queryParams.value.dataType = '2'
total.value = 0
handleQuery()
}
const drawBar = (data) => {
if (document.getElementById('chartBar') === null) {
return
}
echarts.dispose(document.getElementById('chartBar'))
const myChart = echarts.init(document.getElementById('chartBar'))
const option = {
legend: {
// 图示例样式
show: true,
top: 50,
right: 50,
itemGap: 20
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
return params[0].name + '<br>' + '收益:' + params[0].value + '元'
}
},
grid: {
left: '5%',
right: '5%',
bottom: '5%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: data.name,
axisTick: {
alignWithLabel: true // 刻度线是否与标签对齐默认false
},
// 设置 X 轴线条粗细
axisLine: {
lineStyle: {
width: 1, // 根据需求调整数值大小,单位是像素
color: '#999'
}
}
}
],
yAxis: [
{
type: 'value',
axisTick: {
show: false // 默认为true如果要隐藏则改为 false
},
axisLine: {
show: true,
lineStyle: {
width: 1,
color: '#999'
}
}
}
],
series: [
{
data: data.value1,
type: 'bar',
barWidth: 20, // 根据需求调整数值大小,单位是像素
itemStyle: {
// 此处可以是一个固定颜色值,也可以是一个回调函数根据数据动态计算颜色
color: function (params) {
// 这里可以根据需要设置不同的颜色,比如根据数据值
if (params.data <= 0) {
return 'green'
} else if (params.data > 0) {
return 'red'
}
}
}
}
],
// 添加点击事件的处理函数
emphasis: {
// itemStyle: {
// color: '#2283cf',
// barWidth: 20 // 根据需求调整数值大小,单位是像素
// },
// barWidth: 24 // 根据需求调整数值大小,单位是像素
}
}
myChart.setOption(option)
}
const drawLine = (data) => {
if (document.getElementById('chartLine') === null) {
return
}
echarts.dispose(document.getElementById('chartLine'))
const myChart = echarts.init(document.getElementById('chartLine'))
const option = {
grid: {
left: '5%',
right: '5%',
bottom: '5%',
containLabel: true
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
return params[0].name + '<br>' + '收益' + params[0].value + '元'
}
},
xAxis: {
type: 'category',
data: data.name,
axisTick: {
alignWithLabel: true
},
axisLine: {
lineStyle: {
width: 1,
color: '#999'
}
}
},
yAxis: {
type: 'value',
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
width: 1,
color: '#999'
}
}
},
series: [
{
data: data.value1,
type: 'line',
lineStyle: {
color: '#4181c9'
},
itemStyle: {
// 此处可以是一个固定颜色值,也可以是一个回调函数根据数据动态计算颜色
color: function (params) {
// 这里可以根据需要设置不同的颜色,比如根据数据值
if (params.data <= 0) {
return 'green'
} else if (params.data > 0) {
return 'red'
}
}
},
smooth: true,
symbol: 'emptyCircle',
areaStyle: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: 'rgba(65,129,201, 0.70)'
},
{
offset: 1,
color: 'rgba(65,129,201, 0.10)'
}
],
false
),
shadowColor: 'rgba(65,129,201, 0.10)',
shadowBlur: 10
}
}
]
}
myChart.setOption(option)
}
const currentType = ref('柱状图')
const handleRadioChange = (type) => {
currentType.value = type
switch (type) {
case '柱状图':
drawBar(chartData.value)
break
case '折线图':
drawLine(chartData.value)
break
default:
break
}
}
getFutureStocksList()
getList()
</script>