feat: 运营监控页面柱状图表组件封装及页面中引用逻辑调整等

main
weiyin 10 months ago
parent 3eb9b174c6
commit a7c062c4c3

@ -0,0 +1,316 @@
<template>
<div id="main"></div>
</template>
<script>
import * as echarts from "echarts";
//
const leftRect = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
width: 15, //
zWidth: 8, //
zHeight: 4, //
},
buildPath: function (ctx, shape) {
const api = shape.api;
const xAxisPoint = api.coord([shape.xValue, 0]);
const p0 = [shape.x - shape.width / 2, shape.y - shape.zHeight];
const p1 = [shape.x - shape.width / 2, shape.y - shape.zHeight];
const p2 = [xAxisPoint[0] - shape.width / 2, xAxisPoint[1]];
const p3 = [xAxisPoint[0] + shape.width / 2, xAxisPoint[1]];
const p4 = [shape.x + shape.width / 2, shape.y];
ctx.moveTo(p0[0], p0[1]);
ctx.lineTo(p1[0], p1[1]);
ctx.lineTo(p2[0], p2[1]);
ctx.lineTo(p3[0], p3[1]);
ctx.lineTo(p4[0], p4[1]);
ctx.lineTo(p0[0], p0[1]);
ctx.closePath();
},
});
//
const rightRect = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
width: 14,
zWidth: 10,
zHeight: 8,
},
buildPath: function (ctx, shape) {
const api = shape.api;
const xAxisPoint = api.coord([shape.xValue, 0]);
const p1 = [shape.x - shape.width / 2, shape.y - shape.zHeight / 2];
const p3 = [xAxisPoint[0] + shape.width / 2, xAxisPoint[1]];
const p4 = [shape.x + shape.width / 2, shape.y];
const p5 = [xAxisPoint[0] + shape.width / 2 + shape.zWidth, xAxisPoint[1]];
const p6 = [
shape.x + shape.width / 2 + shape.zWidth,
shape.y - shape.zHeight / 2,
];
const p7 = [
shape.x - shape.width / 2 + shape.zWidth,
shape.y - shape.zHeight,
];
ctx.moveTo(p4[0], p4[1]);
ctx.lineTo(p3[0], p3[1]);
ctx.lineTo(p5[0], p5[1]);
ctx.lineTo(p6[0], p6[1]);
ctx.lineTo(p4[0], p4[1]);
ctx.moveTo(p4[0], p4[1]);
ctx.lineTo(p6[0], p6[1]);
ctx.lineTo(p7[0], p7[1]);
ctx.lineTo(p1[0], p1[1]);
ctx.lineTo(p4[0], p4[1]);
ctx.closePath();
},
});
//
echarts.graphic.registerShape("leftRect", leftRect);
echarts.graphic.registerShape("rightRect", rightRect);
export default {
name: "Histogram",
props: {
getDataList: {
type: Array,
default: () => [],
},
},
data() {
return {
labels: ["骨科", "心胸外科", "普通外科", "神经外科", "整形外科"],
seriesData: [
{
label: "骨科",
value: [32],
isHave:false
},
{
label: "心胸外科",
value: [24],
isHave:false
},
{
label: "普通外科",
value: [42],
isHave:false
},
{
label: "神经外科",
value: [20],
isHave:false
},
{
label: "整形外科",
value: [18],
isHave:false
},
],
colors: [
[
{ offset: 0, color: "rgba(26, 132, 191, 1)" },
{ offset: 1, color: "rgba(52, 163, 224, 0.5)" },
],
[
{ offset: 0, color: "rgba(137, 163, 164, 1)" },
{ offset: 1, color: "rgba(137, 163, 164, 0.5)" },
],
[
{ offset: 0, color: "rgba(44, 166, 166, 1)" },
{ offset: 1, color: "rgba(44, 166, 166, 0.5)" },
],
[
{ offset: 0, color: "rgba(34, 66, 186, 1)" },
{ offset: 1, color: "rgba(34, 66, 186, 0.5)" },
],
[
{ offset: 0, color: "rgba(250,200,88, 1)" },
{ offset: 1, color: "rgba(250,200,88, 0.6)" },
],
],
option: {},
};
},
created() {
//
this.wrapData(this.getDataList);
this.option = {
grid: {
height: "80%",
top: "8%",
// bottom: "5%",
},
xAxis: {
axisTick: {
show: false,
},
nameTextStyle: {
color: "#fff",
},
data: this.labels,
axisLabel: {
interval: 0,
rotate: -20, //
color: "#fff",
},
},
legend: {
// data: this.getlegendData(),
// right: "25",
// top: "18",
// icon: "rect",
// itemHeight: 10,
// itemWidth: 10,
// textStyle: {
// color: "red",
// },
show: false,
},
yAxis: {
type: "value",
axisLabel: {
color: "#fff",
},
splitLine: {
show: true,
lineStyle: {
type: "dashed",
color: ["#fff"],
},
},
},
series: this.getSeriesData(),
};
},
methods: {
getlegendData() {
let that = this;
const data = [];
this.labels.forEach((item, index) => {
data.push({
name: item,
itemStyle: {
color: new echarts.graphic.LinearGradient(
1,
0,
0,
0,
that.colors[index]
),
},
});
});
return data;
},
getSeriesData() {
let that = this;
const data = [];
this.seriesData.forEach((item, index) => {
data.push({
type: "custom",
name: item.label,
renderItem: function (params, api) {
return that.getRenderItem(params, api);
},
label: {
show: true, //
position: "insideTop", //
textStyle: {
//
color: "#fff",
},
formatter: function (data) {
let txt = '';
that.seriesData.forEach(a =>{
if (a.label == data.seriesName && !a.isHave) {
a.isHave = true;
txt = data.value;
}
})
return txt;
},
},
data: item.value,
itemStyle: {
color: () => {
return new echarts.graphic.LinearGradient(
0,
0,
0,
1,
that.colors[index]
);
},
},
});
});
console.log("data总:", data);
return data;
},
getRenderItem(params, api) {
const index = params.seriesIndex;
let location = api.coord([api.value(0) + index, api.value(1)]);
// var extent = api.size([0, api.value(1)]);
return {
type: "group",
children: [
{
type: "leftRect",
shape: {
api,
xValue: api.value(0) + index,
yValue: api.value(1),
x: location[0],
y: location[1],
},
style: api.style(),
},
{
type: "rightRect",
shape: {
api,
xValue: api.value(0) + index,
yValue: api.value(1),
x: location[0],
y: location[1],
},
style: api.style(),
},
],
};
},
wrapData(list) {
let that = this;
that.labels = [];
that.seriesData = [];
list.forEach((item) => {
that.labels.push(item.deptName);
that.seriesData.push({
label: item.deptName,
value: [item.deptCount],
isHave:false
});
});
},
},
mounted() {
var chartDom = document.getElementById("main");
var myChart = echarts.init(chartDom);
this.option && myChart.setOption(this.option);
},
};
</script>
<style lang="scss" scoped>
#main {
width: 100%;
height: 100%;
}
</style>

@ -1,80 +1,84 @@
<template> <template>
<div class="w-[51.29vh] h-[40.09vh] bgBottomLeftBox mt-[2.68vh] relative" v-loading="isLoading"> <div
<div class="w-[12.4vh] h-[5.07vh] ml-[1.85vh] flex justify-between items-center"> class="w-[51.29vh] h-[40.09vh] bgBottomLeftBox mt-[2.68vh] relative"
v-loading="isLoading"
>
<div
class="w-[12.4vh] h-[5.07vh] ml-[1.85vh] flex justify-between items-center"
>
<img src="@/assets/svg/Monitor/Triangle.svg" /> <img src="@/assets/svg/Monitor/Triangle.svg" />
<span class="text-[2.03vh] youshe leading-none">手术量统计</span> <span class="text-[2.03vh] youshe leading-none">手术量统计</span>
</div> </div>
<div class="w-[42.96vh] h-[27.12vh] ml-[2.96vh] my-[3.7vh]" ref="echartsContainer"></div> <div class="w-[42.96vh] h-[27.12vh] ml-[2.96vh] my-[3.7vh]">
<div class="absolute right-0 top-1/4 w-[3.51vh] h-[12.6vh]" :class="sliderClass"> <Histogram
<div class="h-[6.3vh] leading-[6.3vh] text-center text-[#C0D3E1] cursor-pointer" @click="toWeek"></div> v-if="getDataList.length"
<div class="h-[6.3vh] leading-[6.3vh] text-center text-[#C0D3E1] cursor-pointer" @click="toMonth"></div> :getDataList="getDataList"
></Histogram>
<div v-else class="flex w-[100%] h-[100%] items-center justify-center">
暂无数据
</div>
</div>
<div
class="absolute right-0 top-1/4 w-[3.51vh] h-[12.6vh]"
:class="sliderClass"
>
<div
class="h-[6.3vh] leading-[6.3vh] text-center text-[#C0D3E1] cursor-pointer"
@click="toWeek"
>
</div>
<div
class="h-[6.3vh] leading-[6.3vh] text-center text-[#C0D3E1] cursor-pointer"
@click="toMonth"
>
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import * as echarts from 'echarts'; import { GetMonitorOperationNumber } from "@/api/monitor";
import { GetMonitorOperationNumber } from '@/api/monitor'; import dayjs from "dayjs";
import { fnR } from '@/utils/common'; import Histogram from "@/components/Histogram.vue";
import dayjs from 'dayjs';
let chartLeft = null;
export default { export default {
data() { data() {
return { return {
chartOptions: { startDate: dayjs().subtract(7, "day").format("YYYY-MM-DD"),
grid: { endDate: dayjs().format("YYYY-MM-DD"),
left: '0%',
right: '0%',
top: '0%',
bottom: '10%',
},
xAxis: {
type: 'category',
data: ['择期手术', '急诊手术', '日间手术', '门诊手术'],
},
yAxis: {
type: 'value',
},
series: [
{
data: [1, 1, 1, 1],
type: 'bar',
barWidth: '10%',
},
],
},
startDate: dayjs().subtract(7, 'day').format('YYYY-MM-DD'),
endDate: dayjs().format('YYYY-MM-DD'),
sliderClass: { sliderClass: {
bgWeekBox: true, bgWeekBox: true,
bgMonthBox: false, bgMonthBox: false,
}, },
renderTimer: null, renderTimer: null,
isLoading: true, isLoading: true,
getDataList: [],
}; };
}, },
components: {
Histogram,
},
methods: { methods: {
onGetPageData() { onGetPageData() {
this.isLoading = true; this.isLoading = true;
GetMonitorOperationNumber({ startDate: this.startDate, endDate: this.endDate }).then(res => { GetMonitorOperationNumber({
this.chartOptions['series'][0]['data'] = [res['data']['ElectiveCount'], res['data']['EmergencyCount'], res['data']['DaySurgeryCount'], res['data']['OutSurgeryCount']]; startDate: this.startDate,
if (this.$store.getters.isMock) { endDate: this.endDate,
let data = [fnR(), fnR(), fnR(), fnR()]; }).then((res) => {
this.chartOptions['series'][0]['data'] = data; this.getDataList = res["data"] || [];
}
this.isLoading = false; this.isLoading = false;
chartLeft.setOption(this.chartOptions);
}); });
}, },
toWeek() { toWeek() {
this.startDate = dayjs().subtract(7, 'day').format('YYYY-MM-DD'); this.startDate = dayjs().subtract(7, "day").format("YYYY-MM-DD");
this.sliderClass.bgWeekBox = true; this.sliderClass.bgWeekBox = true;
this.sliderClass.bgMonthBox = false; this.sliderClass.bgMonthBox = false;
this.onGetPageData(); this.onGetPageData();
}, },
toMonth() { toMonth() {
this.startDate = dayjs().subtract(30, 'day').format('YYYY-MM-DD'); this.startDate = dayjs().subtract(30, "day").format("YYYY-MM-DD");
this.sliderClass.bgWeekBox = false; this.sliderClass.bgWeekBox = false;
this.sliderClass.bgMonthBox = true; this.sliderClass.bgMonthBox = true;
this.onGetPageData(); this.onGetPageData();
@ -82,8 +86,6 @@ export default {
}, },
mounted() { mounted() {
this.onGetPageData(); this.onGetPageData();
chartLeft = echarts.init(this.$refs.echartsContainer);
chartLeft.setOption(this.chartOptions);
this.renderTimer = setInterval(() => { this.renderTimer = setInterval(() => {
if (this.sliderClass.bgWeekBox) { if (this.sliderClass.bgWeekBox) {
this.toMonth(); this.toMonth();
@ -100,18 +102,18 @@ export default {
<style> <style>
.bgBottomLeftBox { .bgBottomLeftBox {
background-image: url('@/assets/svg/Monitor/BottomLeft/Box.svg'); background-image: url("@/assets/svg/Monitor/BottomLeft/Box.svg");
background-size: contain; background-size: contain;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.bgWeekBox { .bgWeekBox {
background-image: url('@/assets/svg/Monitor/BottomLeft/WeekActive.svg'); background-image: url("@/assets/svg/Monitor/BottomLeft/WeekActive.svg");
background-size: contain; background-size: contain;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.bgMonthBox { .bgMonthBox {
background-image: url('@/assets/svg/Monitor/BottomLeft/MonthActive.svg'); background-image: url("@/assets/svg/Monitor/BottomLeft/MonthActive.svg");
} }
</style> </style>

@ -11,10 +11,16 @@
>科室手术量统计(前五)</span >科室手术量统计(前五)</span
> >
</div> </div>
<div <div class="w-[35.46vh] h-[28.05vh] ml-[2.4vh] my-[3.7vh]">
class="w-[35.46vh] h-[28.05vh] ml-[2.4vh] my-[3.7vh]" <!-- <div ref="echartsContainer"></div> -->
ref="echartsContainer" <Histogram
></div> v-if="getDataList.length"
:getDataList="getDataList"
></Histogram>
<div v-else class="flex w-[100%] h-[100%] items-center justify-center">
暂无数据
</div>
</div>
<div <div
class="absolute right-0 top-1/4 w-[3.51vh] h-[12.6vh]" class="absolute right-0 top-1/4 w-[3.51vh] h-[12.6vh]"
:class="sliderClass" :class="sliderClass"
@ -36,49 +42,13 @@
</template> </template>
<script> <script>
import * as echarts from "echarts";
import { GetMonitorOperationDept } from "@/api/monitor"; import { GetMonitorOperationDept } from "@/api/monitor";
import { fnR } from "@/utils/common";
import dayjs from "dayjs"; import dayjs from "dayjs";
let chartLeft = null; import Histogram from "@/components/Histogram.vue";
export default { export default {
data() { data() {
return { return {
chartOptions: {
grid: {
left: "0%",
right: "0%",
top: "0%",
bottom: "10%",
},
xAxis: {
type: "category",
data: ["骨科", "心胸外科", "普通外科", "神经外科", "整形外科"],
},
yAxis: {
type: "value",
},
series: [
{
data: [180, 165, 155, 148, 137],
type: "bar",
barWidth: "10%",
},
],
},
emptyOptions: {
title: {
text: "暂无数据",
x: "center",
y: "center",
textStyle: {
color: "#fff",
fontWeight: "normal",
fontSize: 16,
},
},
},
startDate: dayjs().subtract(7, "day").format("YYYY-MM-DD"), startDate: dayjs().subtract(7, "day").format("YYYY-MM-DD"),
endDate: dayjs().format("YYYY-MM-DD"), endDate: dayjs().format("YYYY-MM-DD"),
sliderClass: { sliderClass: {
@ -90,49 +60,18 @@ export default {
getDataList: [], getDataList: [],
}; };
}, },
components: {
Histogram,
},
methods: { methods: {
onGetPageData() { onGetPageData() {
chartLeft.clear(); //
this.isLoading = true; this.isLoading = true;
GetMonitorOperationDept({ GetMonitorOperationDept({
startDate: this.startDate, startDate: this.startDate,
endDate: this.endDate, endDate: this.endDate,
}).then((res) => { }).then((res) => {
this.getDataList = res["data"] || []; this.getDataList = res["data"] || [];
if (this.getDataList.length) {
this.chartOptions.xAxis.data = [];
this.chartOptions.series[0].data = [];
res["data"].forEach((item) => {
this.chartOptions.xAxis.data.push(item["deptName"]);
this.chartOptions.series[0].data.push(item["deptCount"]);
});
} else {
if (this.$store.getters.isMock) {
this.chartOptions.xAxis.data = [
"骨科",
"心胸外科",
"普通外科",
"神经外科",
"整形外科",
];
this.chartOptions.series[0].data = [
fnR(),
fnR(),
fnR(),
fnR(),
fnR(),
].sort((a, b) => {
return b - a;
});
} else {
//
this.chartOptions.xAxis.data = [];
this.chartOptions.series[0].data = [];
chartLeft.setOption(this.emptyOptions);
}
}
this.isLoading = false; this.isLoading = false;
chartLeft.setOption(this.chartOptions);
}); });
}, },
toWeek() { toWeek() {
@ -149,9 +88,7 @@ export default {
}, },
}, },
mounted() { mounted() {
chartLeft = echarts.init(this.$refs.echartsContainer);
this.onGetPageData(); this.onGetPageData();
chartLeft.setOption(this.chartOptions);
this.renderTimer = setInterval(() => { this.renderTimer = setInterval(() => {
if (this.sliderClass.bgWeekBox) { if (this.sliderClass.bgWeekBox) {
this.toMonth(); this.toMonth();

@ -15,12 +15,13 @@
</template> </template>
<script> <script>
import topLeft from './topLeft/index.vue'; import topLeft from "./topLeft/index.vue";
import topRight from './topRight/index.vue'; import topRight from "./topRight/index.vue";
import bottomLeft from './bottomLeft/index.vue'; import bottomLeft from "./bottomLeft/index.vue";
import bottomMiddle from './bottomMiddle/index.vue'; import bottomMiddle from "./bottomMiddle/index.vue";
import bottomRight from './bottomRight/index.vue'; import bottomRight from './bottomRight/index.vue';
export default { export default {
data() { data() {
return { return {

Loading…
Cancel
Save