重新修改echarts图表使用vue-echarts组件简化

This commit is contained in:
jiangzhe 2024-04-25 10:57:48 +08:00
parent 1d4014aa79
commit 844dd4ad4a
8 changed files with 363 additions and 171 deletions

View File

@ -39,6 +39,7 @@
"vform3-builds": "3.0.8",
"vue": "3.2.45",
"vue-cropper": "1.0.3",
"vue-echarts": "^6.7.1",
"vue-i18n": "9.2.2",
"vue-router": "4.1.4",
"vue-types": "^5.0.3"

View File

@ -71,6 +71,9 @@ dependencies:
vue-cropper:
specifier: 1.0.3
version: 1.0.3
vue-echarts:
specifier: ^6.7.1
version: 6.7.1(echarts@5.4.0)(vue@3.2.45)
vue-i18n:
specifier: 9.2.2
version: 9.2.2(vue@3.2.45)
@ -742,8 +745,8 @@ packages:
vue-i18n:
optional: true
dependencies:
'@intlify/message-compiler': 9.4.1
'@intlify/shared': 9.4.1
'@intlify/message-compiler': 10.0.0-alpha.2
'@intlify/shared': 10.0.0-alpha.2
jsonc-eslint-parser: 1.4.1
source-map: 0.6.1
vue-i18n: 9.2.2(vue@3.2.45)
@ -765,6 +768,14 @@ packages:
dependencies:
'@intlify/shared': 9.2.2
/@intlify/message-compiler@10.0.0-alpha.2:
resolution: {integrity: sha512-OGwttsMwB2BUzhZLraoAfAqcza5UyLMEU013ort3LbmdE6ke/pFONFyxjNQdmFWzW2K868AIVgwx4zo8lbmhjg==}
engines: {node: '>= 16'}
dependencies:
'@intlify/shared': 10.0.0-alpha.2
source-map-js: 1.0.2
dev: true
/@intlify/message-compiler@9.2.2:
resolution: {integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==}
engines: {node: '>= 14'}
@ -772,23 +783,15 @@ packages:
'@intlify/shared': 9.2.2
source-map: 0.6.1
/@intlify/message-compiler@9.4.1:
resolution: {integrity: sha512-aN2N+dUx320108QhH51Ycd2LEpZ+NKbzyQ2kjjhqMcxhHdxtOnkgdx+MDBhOy/CObwBmhC3Nygzc6hNlfKvPNw==}
/@intlify/shared@10.0.0-alpha.2:
resolution: {integrity: sha512-pWlpsC3IqkDuIH/5bNlyyiUbAXYymeNXkznORzPWT3qpAe8MazPOm14wMHGn/wESCdB5b9txQson4+CH0ym1hQ==}
engines: {node: '>= 16'}
dependencies:
'@intlify/shared': 9.4.1
source-map-js: 1.0.2
dev: true
/@intlify/shared@9.2.2:
resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==}
engines: {node: '>= 14'}
/@intlify/shared@9.4.1:
resolution: {integrity: sha512-A51elBmZWf1FS80inf/32diO9DeXoqg9GR9aUDHFcfHoNDuT46Q+fpPOdj8jiJnSHSBh8E1E+6qWRhAZXdK3Ng==}
engines: {node: '>= 16'}
dev: true
/@intlify/unplugin-vue-i18n@0.8.2(vue-i18n@9.2.2):
resolution: {integrity: sha512-cRnzPqSEZQOmTD+p4pwc3RTS9HxreLqfID0keoqZDZweCy/CGRMLLTNd15S4TUf1vSBhPF03DItEFDr1F+8MDA==}
engines: {node: '>= 14.16'}
@ -805,7 +808,7 @@ packages:
optional: true
dependencies:
'@intlify/bundle-utils': 4.0.0(vue-i18n@9.2.2)
'@intlify/shared': 9.4.1
'@intlify/shared': 10.0.0-alpha.2
'@rollup/pluginutils': 4.2.1
'@vue/compiler-sfc': 3.2.45
debug: 4.3.4
@ -4276,6 +4279,10 @@ packages:
engines: {node: '>=0.10'}
dev: true
/resize-detector@0.3.0:
resolution: {integrity: sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ==}
dev: false
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@ -5214,6 +5221,21 @@ packages:
resolution: {integrity: sha512-yDrZkE4H5vOiMA9WQHE+6rmXrZ1S9TMZasEPAZPKg/2I/nySHL4ECD1lNxt7+ofTPKT+9+2sQkCwagPqEqiqJg==}
dev: false
/vue-demi@0.13.11(vue@3.2.45):
resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
dependencies:
vue: 3.2.45
dev: false
/vue-demi@0.14.7(vue@3.2.45):
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
engines: {node: '>=12'}
@ -5228,6 +5250,26 @@ packages:
dependencies:
vue: 3.2.45
/vue-echarts@6.7.1(echarts@5.4.0)(vue@3.2.45):
resolution: {integrity: sha512-HYn54QBk1ILaQ+qA1PQGHwm3MsEFTD5NN9bmgk6wco8LcwKLnRC4HRM0ualYDGOJcCccTpnqD5DvIG0UH1+wDQ==}
requiresBuild: true
peerDependencies:
'@vue/composition-api': ^1.0.5
'@vue/runtime-core': ^3.0.0
echarts: ^5.4.1
vue: ^2.6.12 || ^3.1.1
peerDependenciesMeta:
'@vue/composition-api':
optional: true
'@vue/runtime-core':
optional: true
dependencies:
echarts: 5.4.0
resize-detector: 0.3.0
vue: 3.2.45
vue-demi: 0.13.11(vue@3.2.45)
dev: false
/vue-eslint-parser@9.1.0(eslint@8.36.0):
resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==}
engines: {node: ^14.17.0 || >=16.0.0}

View File

@ -1,15 +1,36 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
/**
*
* @param query
* @returns {*}
*/
export const listWarnRecord = (query: any): AxiosPromise<any[]> => {
export const getCompleteAll = (query: any): AxiosPromise<any[]> => {
return request({
url: '/scale/warn/pageList',
url: '/scale/statistic/complete/all',
method: 'get',
params: query
});
};
export const getCompleteClass = (query: any): AxiosPromise<any[]> => {
return request({
url: '/scale/statistic/complete/class',
method: 'get',
params: query
});
};
export const getWarnAll = (query: any): AxiosPromise<any[]> => {
return request({
url: '/scale/statistic/warn/all',
method: 'get',
params: query
});
};
export const getWarnClass = (query: any): AxiosPromise<any[]> => {
return request({
url: '/scale/statistic/warn/class',
method: 'get',
params: query
});

View File

@ -16,6 +16,14 @@ export const listInterveneRecord = (query?: InterveneRecordQuery): AxiosPromise<
});
};
export const listInterveneTimes = (query?: any): AxiosPromise<any[]> => {
return request({
url: '/scale/intervene/times',
method: 'get',
params: query
});
};
/**
*
* @param interveneId

View File

@ -27,12 +27,6 @@
<el-descriptions-item label="相关量表">
气质类型测试量表
</el-descriptions-item>
<el-descriptions-item label="自动重测">
<el-radio-group v-model="radio">
<el-radio :value="0">禁用</el-radio>
<el-radio :value="1">启用</el-radio>
</el-radio-group>
</el-descriptions-item>
<el-descriptions-item label="活动类型">
普测
</el-descriptions-item>
@ -42,26 +36,13 @@
<el-descriptions-item label="刷新时间">
2024-04-22 142204
</el-descriptions-item>
<el-descriptions-item label="自动刷新">
<el-radio-group v-model="radio">
<el-radio :value="0">禁用</el-radio>
<el-radio :value="1">启用</el-radio>
</el-radio-group>
</el-descriptions-item>
<el-descriptions-item label="施测对象">
学生
</el-descriptions-item>
<el-descriptions-item label="拍照验证">
<el-radio-group v-model="radio">
<el-radio :value="0">禁用</el-radio>
<el-radio :value="1">启用</el-radio>
</el-radio-group>
</el-descriptions-item>
<el-descriptions-item label="参与人员">
五年级一班
</el-descriptions-item>
</el-descriptions>
</el-card>
<el-card style="margin-top: 10px;">

View File

@ -14,7 +14,7 @@
</el-row>
<el-row>
<el-card style="width: 100%; min-height: 300px;margin-top: 20px;">
<el-card style="width: 100%; min-height: 300px;margin-top: 10px;">
<template #header>
<div class="card-header">
<span>完成情况</span>
@ -23,16 +23,16 @@
<el-row justify="space-between">
<el-col :span="8">
<div ref="pieChart" style="height:300px;width:500px;"></div>
<v-chart class="h" :option="completePieOption" autoresize />
</el-col>
<el-col :span="16">
<div ref=barChart style="height: 300px;width:1000px;"></div>
<v-chart class="h" :option="completeBarOption" autoresize />
</el-col>
</el-row>
<el-row justify="center">
<el-table :data="completeTableData" style="width: 100%">
<el-table-column prop="grade" label="年级" />
<el-table :data="completeTable" style="width: 100%">
<el-table-column prop="name" :label="radio == 1 ? '年级' : '班级'" />
<el-table-column prop="join" label="参与人员" />
<el-table-column prop="finish" label="完成人数" />
<el-table-column prop="finishRate" label="完成率" />
@ -43,36 +43,55 @@
</el-row>
<el-row>
<el-card style="width: 100%; min-height: 300px;margin-top: 20px;">
<el-card style="width: 100%; min-height: 300px;margin-top: 10px;">
<template #header>
<div class="card-header">
<span>预警情况</span>
</div>
</template>
<el-row justify="space-between">
<el-col :span="8">
<v-chart class="h" :option="warnPieOption" autoresize />
</el-col>
<el-col :span="16">
<v-chart class="h" :option="warBarOption" autoresize />
</el-col>
</el-row>
<el-row justify="center">
<el-table :data="completeTableData" style="width: 100%;">
<el-table-column prop="grade" label="年级" />
<el-table-column prop="join" label="无风险人数" />
<el-table-column prop="finish" label="低风险人数" />
<el-table-column prop="finish" label="中风险人数" />
<el-table-column prop="finish" label="高风险人数" />
<el-table-column prop="finish" label="严重人数" />
<el-table :data="warnTable" style="width: 100%;">
<el-table-column prop="name" :label="radio == 1 ? '年级' : '班级'" />
<el-table-column prop="noneNum" label="未见异常" />
<el-table-column prop="lowNum" label="低风险" />
<el-table-column prop="middleNum" label="中风险" />
<el-table-column prop="highNum" label="高风险" />
<el-table-column prop="majorNum" label="重大风险" />
</el-table>
</el-row>
</el-card>
</el-row>
<el-row>
<el-card style="width: 100%; min-height: 300px;margin-top: 20px;">
<el-card style="width: 100%; min-height: 300px;margin-top: 10px;">
<template #header>
<div class="card-header">
<span>预警因子类型</span>
</div>
</template>
<el-row justify="space-between">
<el-col :span="8">
<v-chart style="height: 300px;" :option="pieOption" autoresize />
</el-col>
<el-col :span="16">
<v-chart style="height: 300px;" :option="barOption" autoresize />
</el-col>
</el-row>
<el-row justify="center">
<el-table :data="completeTableData" style="width: 100%;">
<el-table-column prop="grade" label="年级" />
<el-table :data="completeTable" style="width: 100%;">
<el-table-column prop="name" :label="radio == 1 ? '年级' : '班级'" />
<el-table-column prop="join" label="参与人员" />
<el-table-column prop="finish" label="完成人数" />
<el-table-column prop="finishRate" label="完成率" />
@ -83,10 +102,17 @@
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts';
import { getScalePublish } from '@/api/scale/scalePublish';
import { getCompleteAll, getCompleteClass, getWarnAll, getWarnClass } from '@/api/activity/statistics'
import { use } from 'echarts/core'
import { CanvasRenderer } from "echarts/renderers";
import { PieChart, BarChart } from "echarts/charts";
import { TitleComponent, TooltipComponent, LegendComponent } from "echarts/components";
import VChart from 'vue-echarts'
const props = defineProps({
batchNo: {
@ -95,102 +121,76 @@ const props = defineProps({
}
})
const batchNo = props.batchNo
console.log('batchNo', batchNo);
const completeTableData = [
{
grade: '三年级',
join: '35',
finish: '3',
finishRate: '1.33%',
},
{
grade: '四年级',
join: '45',
finish: '4',
finishRate: '1.44%',
},
{
grade: '五年级',
join: '55',
finish: '5',
finishRate: '1.55%',
},
{
grade: '六年级',
join: '65',
finish: '6',
finishRate: '1.66%',
},
]
use([
CanvasRenderer,
PieChart,
BarChart,
TitleComponent,
TooltipComponent,
LegendComponent,
]);
const radio = ref(1)
const pieChart = ref()
function initPie() {
const pieChartInstance = echarts.init(pieChart.value)
pieChartInstance.setOption({
const pieOption = ref({
title: {
text: 'Traffic Sources',
left: 'center',
},
tooltip: {
trigger: 'item'
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)',
},
legend: {
orient: 'vertical',
left: 'left'
left: 'left',
data: ['Direct', 'Email', 'Ad Networks', 'Video Ads', 'Search Engines'],
},
series: [
{
name: '完成情况',
name: 'Traffic Sources',
type: 'pie',
radius: '50%',
radius: '55%',
center: ['50%', '60%'],
data: [
{ value: 1048, name: '已测' },
{ value: 300, name: '未测' }
{ value: 335, name: 'Direct' },
{ value: 310, name: 'Email' },
{ value: 234, name: 'Ad Networks' },
{ value: 135, name: 'Video Ads' },
{ value: 1548, name: 'Search Engines' },
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
})
}
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
},
],
});
const barChart = ref()
function initBar() {
const barChartInstance = echarts.init(barChart.value)
barChartInstance.setOption({
legend: {},
const barOption = ref({
xAxis: {
type: 'category',
data: ['一年级', '二年级', '三年级', '四年级', '五年级', '初一', '初二']
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
name: '完成',
data: [12, 20, 15, 8, 7, 11, 13],
type: 'bar'
},
{
name: '未完成',
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}
]
})
}
const batchNo = props.batchNo
const radio = ref(1)
const scaleId = ref()
const scaleList = ref([])
async function getScalePublishList() {
const res = await getScalePublish(batchNo)
console.log('res', res);
const scaleIds = res.data.scaleIds
const scaleNames = res.data.scaleNames
scaleIds.forEach((item, index) => {
@ -202,15 +202,164 @@ async function getScalePublishList() {
}
}
//
const completePieOption = ref(initPieOption('完成情况', []))
const completeBarOption = ref(initBarOption([], []))
const completeTable = ref([])
async function getCompleteData() {
const query = { batchNo, scaleId: scaleId.value }
let res = {}
if (radio.value == 1) {
res = await getCompleteAll(query)
}
if (radio.value == 2) {
res = await getCompleteClass(query)
}
const completeList = res.data
let finishNum = 0
let noneNum = 0
let xAxisData = []
let seriesFinishData = []
let seriesNoneData = []
completeList.forEach(v => {
finishNum += v.value
noneNum += v.spareValue
xAxisData.push(v.name)
seriesFinishData.push(v.value)
seriesNoneData.push(v.spareValue)
completeTable.value.push({ name: v.name, join: v.value + v.spareValue, finish: v.value, finishRate: percentage(v.value, v.value + v.spareValue) })
})
const completePie = [{ name: '已测', value: finishNum }, { name: '未测', value: noneNum }]
completePieOption.value.series[0].data = completePie
const seriesData = [{ name: '已测', data: seriesFinishData, type: 'bar' }, { name: '未测', data: seriesNoneData, type: 'bar' }]
completeBarOption.value.xAxis.data = xAxisData
completeBarOption.value.series = seriesData
}
//
const warnPieOption = ref(initPieOption('预警情况', []))
const warBarOption = ref(initBarOption([], []))
const warnTable = ref([])
async function getwarnData() {
const query = { batchNo, scaleId: scaleId.value }
let res = {}
if (radio.value == 1) {
res = await getWarnAll(query)
}
if (radio.value == 2) {
res = await getWarnClass(query)
}
const warnList = res.data
let noneNum = 0
let lowNum = 0
let middleNum = 0
let highNum = 0
let majorNum = 0
warnList.forEach(v => {
noneNum += v.noneNum
lowNum += v.lowNum
middleNum += v.middleNum
highNum += v.highNum
majorNum += v.majorNum
warnTable.value.push({ name: v.name, noneNum: v.noneNum, lowNum: v.lowNum, middleNum: v.middleNum, highNum: v.highNum, majorNum: v.majorNum })
})
const warnPie = [
{ name: '未见异常', value: noneNum },
{ name: '低风险', value: lowNum },
{ name: '中风险', value: middleNum },
{ name: '高风险', value: highNum },
{ name: '重大风险', value: majorNum }
]
warnPieOption.value.series[0].data = warnPie
let xAxisData = ['未见异常', '低风险', '中风险', '高风险', '重大风险']
let seriesList = [noneNum, lowNum, middleNum, highNum, majorNum]
const seriesData = [{ data: seriesList, type: 'bar' }]
warBarOption.value.xAxis.data = xAxisData
warBarOption.value.series = seriesData
}
watch([scaleId, radio], ([newVal, oldVal]) => {
completeTable.value = []
getCompleteData()
warnTable.value = []
getwarnData()
})
onMounted(() => {
getScalePublishList()
setTimeout(() => {
initPie()
initBar()
}, 1000);
})
function initPieOption(name, data) {
return {
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: name,
type: 'pie',
radius: '50%',
data: data,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
}
function initBarOption(xAxisData, seriesData) {
return {
tooltip: {
trigger: 'item'
},
legend: {},
xAxis: {
type: 'category',
data: xAxisData
},
yAxis: {
type: 'value'
},
series: seriesData
}
}
function percentage(number1, number2) {
//
return (Math.round(number1 / number2 * 10000) / 100.00 + "%");
}
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.h {
height: 300px;
}
</style>

View File

@ -82,23 +82,8 @@
<el-dialog title="干预详情" v-model="listDialog" width="600px" append-to-body>
<el-timeline style="max-width: 600px">
<el-timeline-item timestamp="2018/4/12" placement="top">
<el-card>
<h4>Update Github template</h4>
<p>Tom committed 2018/4/12 20:46</p>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="2018/4/3" placement="top">
<el-card>
<h4>Update Github template</h4>
<p>Tom committed 2018/4/3 20:46</p>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="2018/4/2" placement="top">
<el-card>
<h4>Update Github template</h4>
<p>Tom committed 2018/4/2 20:46</p>
</el-card>
<el-timeline-item :timestamp="item.time" placement="top" v-for="item in timeList" :key="item.id">
{{ item.name }}
</el-timeline-item>
</el-timeline>
</el-dialog>
@ -109,7 +94,7 @@
import { listWarnRecord } from '@/api/archive/warnRecord';
import { WarnRecordVO, WarnRecordQuery, WarnRecordForm } from '@/api/archive/warnRecord/types';
import { addInterveneRecord } from '@/api/archive/interveneRecord';
import { addInterveneRecord, listInterveneTimes } from '@/api/archive/interveneRecord';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -217,7 +202,12 @@ const handleUpdate = async (row?: WarnRecordVO) => {
dialog.visible = true
}
function handleList(row) {
const timeList = ref<any[]>([])
async function handleList(row: any) {
const userId = row.userId
const res = await listInterveneTimes({ userId })
timeList.value = res.data
listDialog.value = true
}

View File

@ -220,7 +220,7 @@ const handleSelectionChange = (selection: SysScaleVO[]) => {
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = "添加心理测评量";
dialog.title = "量表测评发布";
}
/** 提交按钮 */