Files
intc-vue3/src/views/invest/debitDealAnalysis/index.vue
2024-05-04 08:55:55 +08:00

527 lines
16 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="储蓄账户" style="width: 480px" prop="id">
<el-select v-model="queryParams.id" placeholder="请选择储蓄账户" clearable>
<el-option v-for="account in accountsList" :key="account.id" :label="account.nameCode" :value="account.id" />
</el-select>
</el-form-item>
<el-form-item label="交易类型" style="width: 300px" prop="dealType">
<el-select v-model="queryParams.dealType" placeholder="请选择交易类型" clearable>
<el-option v-for="dict in deal_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="交易类别" style="width: 300px" prop="dealCategory">
<el-select v-model="queryParams.dealCategory" placeholder="请选择交易类别" clearable>
<el-option v-for="dict in deal_category" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="" style="width: 100px" 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"
@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="5"
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% - 1.45rem)">
<div class="summary-con">
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">交易金额</div>
<div>
<span class="num">{{ account.amount }}</span> <span class="unit"></span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">收入金额</div>
<div>
<span class="num">{{ account.income }}</span> <span class="unit"></span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">支出金额</div>
<div>
<span class="num">{{ account.expenses }}</span> <span class="unit"></span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">支出笔数</div>
<div>
<span class="num">{{ account.expensesCount }}</span> <span class="unit"></span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">收入笔数</div>
<div>
<span class="num">{{ account.incomeCount }}</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="account.tableAccountsList" 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>
</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 { getAcccountsDealAnalysis } from '@/api/invest/statisticAnalysis'
import { listAccounts } from '@/api/invest/accounts'
const { proxy } = getCurrentInstance()
const { deal_type, account_type, deal_category } = proxy.useDict('deal_type', 'account_type', 'deal_category')
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 > 5) {
ElMessage.warning('时间跨度不能大于5年默认选择开始日期的5年')
queryParams.value.time = [new Date(startYear, 0, 1), new Date(startYear + 5, 0, 1)]
}
}
const dates = [
{ value: 1, label: '日' },
{ value: 2, label: '月' },
{ value: 3, label: '年' }
]
const accountsList = ref([])
const loading = ref(true)
const total = ref(0)
const radioVal = 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(23, 'months')]
ElMessage.warning(message)
}
}
}
const data = reactive({
queryParams: {
type: 1,
time: null,
id: null,
dataType: '1',
dealType: null,
dealCategory: null
},
queryAcccountsParams: {
pageNum: 1,
type: '1',
state: '1',
pageSize: 1000
},
rules: {
time: [{ validator: dateValidate, dateType: 'months', num: 23, dateRange: '月', message: '时间跨度不能大于24个月默认选择开始日期的24个月' }]
}
})
const { queryParams, queryAcccountsParams, rules } = toRefs(data)
const today = new Date()
const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2) + '-' + ('0' + today.getDate()).slice(-2)
const start = dayjs(end).add(-6, 'day')
queryParams.value.time = [start, end]
const handleTimeChange = (type) => {
queryParams.value.time = null
if (type === 1) {
const today = new Date()
const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2) + '-' + ('0' + today.getDate()).slice(-2)
const start = dayjs(end).add(-6, 'day')
queryParams.value.time = [start, end]
} else if (type === 2) {
const today = new Date()
const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2)
const start = dayjs(end).add(-11, 'months')
queryParams.value.time = [start, end]
} else if (type === 3) {
const today = new Date()
const endYear = today.getFullYear()
queryParams.value.time = [new Date(endYear - 2, 0, 1), new Date(endYear, 0, 1)]
showYearValue.value = { startShowYear: endYear - 2, 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 account = ref({
amount: '',
income: '',
expenses: '',
incomeCount: '',
expensesCount: '',
acccountsList: []
})
const chartData = ref({
name: [],
value1: []
})
/** 查询管理列表 */
function getAcccountsList() {
listAccounts(queryAcccountsParams.value).then((response) => {
accountsList.value = response.rows
})
}
function getList() {
loading.value = true
chartData.value = { name: [], value1: [] }
const { type, time, id, dataType, dealType, dealCategory } = 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,
dealType,
dealCategory
}
getAcccountsDealAnalysis(params).then((response) => {
loading.value = false
account.value = { ...response.data }
account.value.acccountsList.map((item) => {
return {
name: item.time,
value: item.value
}
})
response.data.acccountsList.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
const today = new Date()
const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2) + '-' + ('0' + today.getDate()).slice(-2)
const start = dayjs(end).add(-6, 'day')
queryParams.value.time = [start, end]
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: '#2283cf'
}
}
],
// 添加点击事件的处理函数
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: '#4181c9'
},
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
}
}
getAcccountsList()
getList()
</script>