wip: 重构运营监控可视化页面

main
shengwen.chen 4 months ago
parent a539cc3f9b
commit 2323ae998d

@ -13,22 +13,22 @@ export default {
},
methods: {
enterFullscreen() {
const element = document.documentElement;
//
if (!this.isLoding) {
if (element.webkitRequestFullscreen) {
// Chrome, Safari and Opera
element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) {
// IE/Edge
element.msRequestFullscreen();
} else if (element.mozRequestFullScreen) {
// Firefox
element.mozRequestFullScreen();
} else if (element.requestFullscreen) {
element.requestFullscreen();
}
}
// const element = document.documentElement;
// if (!this.isLoding) {
// if (element.webkitRequestFullscreen) {
// // Chrome, Safari and Opera
// element.webkitRequestFullscreen();
// } else if (element.msRequestFullscreen) {
// // IE/Edge
// element.msRequestFullscreen();
// } else if (element.mozRequestFullScreen) {
// // Firefox
// element.mozRequestFullScreen();
// } else if (element.requestFullscreen) {
// element.requestFullscreen();
// }
// }
},
},
};
@ -39,6 +39,7 @@ export default {
font-family: 'PanMen';
src: url('@/assets/fonts/PanMen.ttf') format('opentype');
}
@font-face {
font-family: 'YouSheBiaoTiHei';
src: url('@/assets/fonts/YouSheBiaoTiHei.ttf') format('opentype');
@ -51,6 +52,7 @@ export default {
.youshe {
font-family: 'YouSheBiaoTiHei';
}
* {
color: #fff;
// 线

@ -35,10 +35,7 @@ export const getAudio = (data) => {
...data,
},
{
headers: {
"Content-Type": "application/json",
},
responseType: "blob",
responseType: "blob",
}
);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 802 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

@ -1,3 +0,0 @@
@function vh($px) {
@return $px/1080 * 100vh;
}

@ -0,0 +1,7 @@
@function vh($px) {
@return $px/1080 * 100vh;
}
@function vw($px) {
@return $px / 1920 * 100vw;
}

@ -1,13 +1,8 @@
<template>
<header class="pt-[4.5vh]">
<div class="text-[3.5vh] text-center youshe leading-none">{{ $route.meta.title }}</div>
<div class="flex justify-between items-center px-[5vh] mt-[-1.6vh]">
<div class="flex items-end">
<img src="@/assets/svg/Cloud.svg" />
<span class="text[1.6vh] ml-[0.3vh]">多云转阴 17-34°C</span>
</div>
<div class="text[1.48vh]">{{ curTime }}</div>
</div>
<header>
<div class="left"></div>
<div class="mid">{{ $route.meta.title }}</div>
<div class="right">{{ curTime }}</div>
</header>
</template>
@ -64,4 +59,6 @@ export default {
};
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
@import "./index.scss";
</style>

@ -0,0 +1,25 @@
header {
display: flex;
justify-content: space-between;
align-items: center;
height: vh(88);
padding: 0 vw(50);
.left {
width: vw(264);
}
.mid {
font-size: vw(40);
font-weight: 700;
letter-spacing: vw(8);
color: #5B458D;
}
.right {
font-size: vw(16);
font-weight: 700;
letter-spacing: vw(2);
color: #5B458D;
}
}

@ -7,7 +7,7 @@ const routes = [
{
path: '/',
name: 'home',
redirect: '/monitor',
redirect: '/pagemonitor',
},
{
path: '/pageBox',

@ -0,0 +1,19 @@
#pageBox {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("@/assets/img/bg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}

@ -3,7 +3,7 @@
<div class="wrapper">
<comHeader></comHeader>
<!-- <main class="mt-[4.8vh]"> -->
<main class="mt-[2%]">
<main class="mt-[2.6%]">
<router-view></router-view>
</main>
</div>
@ -20,24 +20,5 @@ export default {
</script>
<style lang="scss" scoped>
#pageBox {
// padding-top: 56.26%;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("@/assets/img/bg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center top;
}
@import "./index.scss";
</style>

@ -1,347 +0,0 @@
<template>
<div id="opMain"></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: "OpHistogram",
props: {
getDataList: {
type: Array,
default: () => [],
},
},
data() {
return {
labels: ["择期", "急诊", "日间", "门诊"],
fields: [
"electiveCount",
"emergencyCount",
"daySurgeryCount",
"outSurgeryCount",
],
seriesData: [
{
label: "择期",
value: [54],
isHave: false,
},
{
label: "急诊",
value: [35],
isHave: false,
},
{
label: "日间",
value: [19],
isHave: false,
},
{
label: "门诊",
value: [60],
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)" },
],
],
option: {},
myChart: null,
};
},
watch: {
getDataList(newVal) {
if (this.$store.getters.isMock) {
return;
}
if (newVal.length) {
this.wrapData(newVal);
this.initOption();
//
this.option && this.myChart && this.myChart.setOption(this.option);
}
},
},
created() {
// --
if (this.getDataList.length) {
if (this.$store.getters.isMock) {
console.log("sssxx");
} else {
this.wrapData(this.getDataList);
}
}
this.initOption();
},
methods: {
initOption() {
this.option = {
grid: {
height: "80%",
top: "8%",
right: 0,
// bottom: "5%",
},
xAxis: {
axisTick: {
show: false,
},
nameTextStyle: {
color: "#fff",
},
data: this.labels,
axisLabel: {
interval: 0,
rotate: 0, //
color: "#fff",
padding: [0, 0, 0, 8],
},
},
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(),
};
},
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: "outsideTop", //
textStyle: {
//
color: "#fff",
padding: [0, 0, 0, 7],
},
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]
);
},
shadowBlur: 8,
shadowColor: "rgba(255,255,255,.4)",
borderColor: "rgba(255,255,255,.6)",
borderWidth: 0.4,
},
});
});
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.fields.forEach((a, index) => {
for (let key in item) {
if (a == key) {
that.seriesData.push({
label: that.labels[index],
value: [item[key]],
isHave: false,
});
}
}
});
});
},
},
mounted() {
var chartDom = document.getElementById("opMain");
this.myChart = echarts.init(chartDom);
this.option && this.myChart.setOption(this.option);
},
};
</script>
<style lang="scss" scoped>
#opMain {
width: 100%;
height: 100%;
}
</style>

@ -0,0 +1,92 @@
.box {
width: vw(552);
height: vh(438);
box-sizing: border-box;
border: 2px solid #DFE0F3;
box-shadow: 2px 4px 20px 0px rgba(87, 68, 175, 0.2);
background: linear-gradient(180deg, rgba(240, 243, 253, 0.95) 0%, rgba(232, 238, 253, 0.95) 100%);
border-radius: vw(8);
padding: vh(16) vw(8);
position: relative;
header {
height: vh(48);
background-image: url("@/assets/img/pageMonitor/headerLine.png");
background-size: contain;
background-repeat: no-repeat;
background-position: center bottom;
div {
width: vw(200);
height: vh(40);
background-image: url("@/assets/img/pageMonitor/headerBg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
margin-left: vw(12);
display: flex;
align-items: center;
p {
color: #444444;
font-size: vw(22);
padding-left: vw(32);
}
}
}
main {
height: vh(350);
}
.sidebar {
position: absolute;
right: -1px;
top: 16%;
>div {
width: vw(40);
height: vh(70);
background: #E9E4FF;
display: flex;
justify-content: center;
position: relative;
z-index: 10;
span {
color: rgba(90, 73, 173, 0.5);
font-size: vw(16);
}
&:first-of-type {
transform: skewY(-30deg);
span {
transform: skewY(30deg);
line-height: vh(60);
}
}
&:last-of-type {
margin-top: vw(-24);
transform: skewY(30deg);
span {
transform: skewY(-30deg);
line-height: vh(90);
}
}
&.active {
background: #5C4BAD;
z-index: 1;
height: vh(82);
span {
color: #fff;
}
}
}
}
}

@ -1,109 +1,38 @@
<template>
<div class="w-[51.29vh] h-[40.09vh] bgBottomLeftBox mt-[2.68vh] relative">
<div class="w-[45%] h-[5.07vh] ml-[1.85vh] flex justify-between items-center">
<img src="@/assets/svg/Monitor/Triangle.svg" />
<span class="text-[2.03vh] youshe leading-none">科室手术量统计(前五)</span>
</div>
<div class="w-[42.96vh] ml-[2.96vh] deptBody">
<div class="h-[30vh] w-full">
<Histogram v-if="getDataList.length" :getDataList="getDataList"></Histogram>
<div v-else class="flex flex-col w-[100%] h-[100%] items-center justify-center">
<img src="@/assets/img/noData.png" class="w-[120px]" />
<span>暂无数据</span>
</div>
<div class="box">
<header>
<div>
<p class="panmen">手术量统计</p>
</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>
</header>
<main>
</main>
<section class="sidebar ">
<div class="top" :class="{ 'active': active == 'week' }" @click="changeActive('week')">
<span></span>
</div>
<div class="bottom" :class="{ 'active': active == 'month' }" @click="changeActive('month')">
<span></span>
</div>
</section>
</div>
</template>
<script>
import { GetMonitorOperationDept } from '@/api/monitor';
import dayjs from 'dayjs';
import Histogram from '@/views/pageMonitor/bottomRight/DepHistogram.vue';
export default {
data() {
return {
startDate: dayjs().subtract(7, 'day').format('YYYY-MM-DD'),
endDate: dayjs().format('YYYY-MM-DD'),
sliderClass: {
bgWeekBox: true,
bgMonthBox: false,
},
renderTimer: null,
isLoading: true,
getDataList: [],
active: 'week'
};
},
components: {
Histogram,
},
methods: {
onGetPageData() {
this.isLoading = true;
GetMonitorOperationDept({
startDate: this.startDate,
endDate: this.endDate,
}).then(res => {
// this.getDataList = [res["data"]] || [];
// this.isLoading = false;
this.getDataList = res['data'] || [];
this.isLoading = false;
});
},
toWeek() {
this.startDate = dayjs().subtract(7, 'day').format('YYYY-MM-DD');
this.sliderClass.bgWeekBox = true;
this.sliderClass.bgMonthBox = false;
this.onGetPageData();
},
toMonth() {
this.startDate = dayjs().subtract(30, 'day').format('YYYY-MM-DD');
this.sliderClass.bgWeekBox = false;
this.sliderClass.bgMonthBox = true;
this.onGetPageData();
},
},
mounted() {
this.onGetPageData();
this.renderTimer = setInterval(() => {
if (this.sliderClass.bgWeekBox) {
this.toMonth();
} else {
this.toWeek();
}
}, this.$store.getters.intervalTime);
},
beforeRouteLeave() {
clearInterval(this.renderTimer);
},
changeActive(newActive) {
this.active = newActive
}
}
};
</script>
<style>
.bgBottomLeftBox {
background-image: url('@/assets/svg/Monitor/BottomLeft/Box.svg');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.bgWeekBox {
background-image: url('@/assets/svg/Monitor/BottomLeft/WeekActive.svg');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.bgMonthBox {
background-image: url('@/assets/svg/Monitor/BottomLeft/MonthActive.svg');
}
.deptBody {
height: calc(100% - 5.07vh);
display: flex;
justify-content: center;
align-items: center;
}
<style lang="scss" scoped>
@import './index.scss'
</style>

@ -1,400 +0,0 @@
<template>
<div class="w-[71.58vh] h-[40.09vh] bgBottomMidBox mt-[2.68vh] relative">
<div class="flex">
<div class="w-[12.4vh] h-[5.07vh] ml-[1.85vh] flex justify-between items-center">
<img src="@/assets/svg/Monitor/Triangle.svg" />
<span class="text-[2.03vh] youshe leading-none">手术等级</span>
</div>
<div class="w-[12.4vh] h-[5.07vh] ml-[27vh] flex justify-between items-center">
<img src="@/assets/svg/Monitor/Triangle.svg" />
<span class="text-[2.03vh] youshe leading-none">ASA分级</span>
</div>
</div>
<section class="flex pt-[4.81vh] relative showBox">
<div class="absolute title">
<span title="手术等级">今日</span>
<span title="ASA分级">今日</span>
</div>
<div class="w-[35.79vh] h-[24.62vh] border-r border-dashed border-r-[rgba(255,255,255,0.26)]">
<div class="h-full" ref="echartsContainerLeft"></div>
</div>
<div class="w-[35.79vh] h-[24.62vh]">
<div class="h-full" ref="echartsContainerRight"></div>
</div>
</section>
</div>
</template>
<script>
import * as echarts from 'echarts';
import { GetMonitorOperationLevel, GetMonitorOperationASALevel } from '@/api/monitor';
import { fnR } from '@/utils/common';
import dayjs from 'dayjs';
let chartLeft = null;
let chartRight = null;
export default {
data() {
return {
nowIndex: 0,
chartOptionsLeft: {
series: [
{
type: 'pie',
radius: ['32%', '50%'],
selectedMode: 'single',
data: [
{ name: '一级', value: 148, selected: false },
{ name: '二级', value: 87, selected: false },
{ name: '三级', value: 75, selected: false },
{ name: '四级', value: 40, selected: false },
],
label: {
formatter: '{b}{c}',
color: 'inherit',
},
labelLine: {
show: true,
length: 15,
length2: 18,
smooth: 0.6, // 使线使
},
padAngle: 5,
itemStyle: {
borderRadius: 10,
},
},
{
name: '外边框-outBig',
type: 'pie',
clockWise: false, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['62%', '62%'],
label: {
normal: {
show: false,
},
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#2F58B4',
},
},
},
],
},
{
name: '外边框-outSmall',
type: 'pie',
clockWise: false, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['57%', '57%'],
label: {
normal: {
show: false,
},
},
showEmptyCircle: true,
itemStyle: {
shadowColor: 'rgba(255, 0, 0, 1)',
shadowBlur: 10,
opacity: 1,
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#0D447C',
},
},
},
],
},
{
name: '内边框-inBig',
type: 'pie',
clockWise: true, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['25%', '25%'],
label: {
normal: {
show: false,
},
},
itemStyle: {
shadowColor: 'rgba(255, 0, 0, 1)',
shadowBlur: 10,
opacity: 1,
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#006CFF',
opacity: 0.4,
},
},
},
],
},
{
name: '内边框-inSmall',
type: 'pie',
clockWise: true, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['20%', '20%'],
label: {
normal: {
show: false,
},
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#fff',
opacity: 0.2,
},
},
},
],
},
],
},
chartOptionsRight: {
series: [
{
type: 'pie',
radius: ['32%', '50%'],
selectedMode: 'single',
data: [
{ name: 'I级', value: 137, selected: false },
{ name: 'II级', value: 105, selected: false },
{ name: 'III级', value: 58, selected: false },
{ name: 'IV级', value: 37, selected: false },
{ name: 'V级', value: 13, selected: false },
],
label: {
formatter: '{b}{c}',
color: 'inherit',
},
labelLine: {
show: true,
length: 15,
length2: 18,
smooth: 0.6, // 使线使
},
padAngle: 5,
itemStyle: {
borderRadius: 10,
},
},
{
name: '外边框-outBig',
type: 'pie',
clockWise: false, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['62%', '62%'],
label: {
normal: {
show: false,
},
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#2F58B4',
},
},
},
],
},
{
name: '外边框-outSmall',
type: 'pie',
clockWise: false, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['57%', '57%'],
label: {
normal: {
show: false,
},
},
showEmptyCircle: true,
itemStyle: {
shadowColor: 'rgba(255, 0, 0, 1)',
shadowBlur: 10,
opacity: 1,
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#0D447C',
},
},
},
],
},
{
name: '内边框-inBig',
type: 'pie',
clockWise: true, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['25%', '25%'],
label: {
normal: {
show: false,
},
},
itemStyle: {
shadowColor: 'rgba(255, 0, 0, 1)',
shadowBlur: 10,
opacity: 1,
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#006CFF',
opacity: 0.4,
},
},
},
],
},
{
name: '内边框-inSmall',
type: 'pie',
clockWise: true, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['20%', '20%'],
label: {
normal: {
show: false,
},
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#fff',
opacity: 0.2,
},
},
},
],
},
],
},
toDate: dayjs().format('YYYY-MM-DD'),
};
},
methods: {
onGetPageData() {
this.isLoading = true;
Promise.all([GetMonitorOperationLevel(this.toDate), GetMonitorOperationASALevel(this.toDate)]).then(res => {
this.chartOptionsLeft.series[0].data[0].value = res[0].data['level1'];
this.chartOptionsLeft.series[0].data[1].value = res[0].data['level2'];
this.chartOptionsLeft.series[0].data[2].value = res[0].data['level3'];
this.chartOptionsLeft.series[0].data[3].value = res[0].data['level4'];
this.chartOptionsRight.series[0].data[0].value = res[1].data['asaLevel1'];
this.chartOptionsRight.series[0].data[1].value = res[1].data['asaLevel2'];
this.chartOptionsRight.series[0].data[2].value = res[1].data['asaLevel3'];
this.chartOptionsRight.series[0].data[3].value = res[1].data['asaLevel4'];
this.chartOptionsRight.series[0].data[4].value = res[1].data['asaLevel5'];
if (this.$store.getters.isMock) {
this.chartOptionsLeft.series[0].data[0].value = fnR();
this.chartOptionsLeft.series[0].data[1].value = fnR();
this.chartOptionsLeft.series[0].data[2].value = fnR();
this.chartOptionsLeft.series[0].data[3].value = fnR();
this.chartOptionsRight.series[0].data[0].value = fnR();
this.chartOptionsRight.series[0].data[1].value = fnR();
this.chartOptionsRight.series[0].data[2].value = fnR();
this.chartOptionsRight.series[0].data[3].value = fnR();
this.chartOptionsRight.series[0].data[4].value = fnR();
}
chartLeft.setOption(this.chartOptionsLeft);
chartRight.setOption(this.chartOptionsRight);
this.isLoading = false;
});
},
},
mounted() {
chartLeft = echarts.init(this.$refs.echartsContainerLeft);
chartLeft.setOption(this.chartOptionsLeft);
chartRight = echarts.init(this.$refs.echartsContainerRight);
chartRight.setOption(this.chartOptionsRight);
this.onGetPageData();
setInterval(() => {
this.onGetPageData();
}, this.$store.getters.intervalTime);
},
};
</script>
<style>
.bgBottomMidBox {
background-image: url('@/assets/svg/Monitor/BottomMid/Box.svg');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.showBox {
}
.showBox .title {
left: 0;
top: 10px;
display: flex;
width: 100%;
justify-content: space-between;
padding: 0 3px;
}
.showBox .title span {
width: 25px;
display: flex;
justify-content: center;
align-items: center;
background: #380aaa;
text-align: center;
color: rgb(192 211 225);
}
</style>

@ -1,344 +0,0 @@
<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: "DepHistogram",
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: {},
myChart: null,
};
},
watch: {
getDataList(newVal) {
if (this.$store.getters.isMock) {
return;
}
if (newVal.length) {
this.wrapData(newVal);
this.initOption();
//
this.option && this.myChart && this.myChart.setOption(this.option);
}
},
},
created() {
// --
if (this.getDataList.length) {
if (this.$store.getters.isMock) {
console.log("sssxx");
} else {
this.wrapData(this.getDataList);
}
}
this.initOption();
},
methods: {
initOption() {
this.option = {
grid: {
height: "80%",
top: "8%",
right: 0,
bottom: 0,
// 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(),
};
},
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",
padding: [0, 0, 0, 7],
},
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]
);
},
shadowBlur: 8,
shadowColor: 'rgba(255,255,255,.4)',
borderColor: "rgba(255,255,255,.6)",
borderWidth: 0.4,
},
});
});
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");
this.myChart = echarts.init(chartDom);
this.option && this.myChart.setOption(this.option);
},
};
</script>
<style lang="scss" scoped>
#main {
width: 100%;
height: 100%;
}
</style>

@ -0,0 +1,165 @@
.boxWrap {
width: vw(1280);
height: vh(438);
display: flex;
justify-content: space-between;
align-items: center;
.opGradeBox {
width: vw(340);
height: 100%;
header {
height: vh(48);
background-image: url("@/assets/img/pageMonitor/headerLine.png");
background-size: contain;
background-repeat: no-repeat;
background-position: center bottom;
div {
width: vw(200);
height: vh(40);
background-image: url("@/assets/img/pageMonitor/headerBg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
margin-left: vw(12);
display: flex;
align-items: center;
p {
color: #444444;
font-size: vw(22);
padding-left: vw(32);
}
}
}
}
.asaGradeBox {
width: vw(340);
height: 100%;
header {
height: vh(48);
background-image: url("@/assets/img/pageMonitor/headerLine.png");
background-size: contain;
background-repeat: no-repeat;
background-position: center bottom;
div {
width: vw(200);
height: vh(40);
background-image: url("@/assets/img/pageMonitor/headerBg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
margin-left: vw(12);
display: flex;
align-items: center;
p {
color: #444444;
font-size: vw(22);
padding-left: vw(32);
}
}
}
}
.opstatisticBox {
width: vw(552);
height: 100%;
header {
height: vh(48);
background-image: url("@/assets/img/pageMonitor/headerLine.png");
background-size: contain;
background-repeat: no-repeat;
background-position: center bottom;
div {
width: vw(300);
height: vh(40);
background-image: url("@/assets/img/pageMonitor/headerBg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
margin-left: vw(12);
display: flex;
align-items: center;
p {
color: #444444;
font-size: vw(22);
padding-left: vw(32);
}
}
}
.sidebar {
position: absolute;
right: -1px;
top: 16%;
>div {
width: vw(40);
height: vh(70);
background: #E9E4FF;
display: flex;
justify-content: center;
position: relative;
z-index: 10;
span {
color: rgba(90, 73, 173, 0.5);
font-size: vw(16);
}
&:first-of-type {
transform: skewY(-30deg);
span {
transform: skewY(30deg);
line-height: vh(60);
}
}
&:last-of-type {
margin-top: vw(-24);
transform: skewY(30deg);
span {
transform: skewY(-30deg);
line-height: vh(90);
}
}
&.active {
background: #5C4BAD;
z-index: 1;
height: vh(82);
span {
color: #fff;
}
}
}
}
}
.box {
box-sizing: border-box;
border: 2px solid #DFE0F3;
box-shadow: 2px 4px 20px 0px rgba(87, 68, 175, 0.2);
background: linear-gradient(180deg, rgba(240, 243, 253, 0.95) 0%, rgba(232, 238, 253, 0.95) 100%);
border-radius: vw(8);
padding: vh(16) vw(8);
position: relative;
}
main {
height: vh(350);
}
}

@ -1,110 +1,390 @@
<template>
<div class="w-[41.75vh] h-[40.09vh] bgBottomRightBox mt-[2.68vh] relative">
<div class="w-[34%] h-[5.07vh] ml-[1.85vh] flex justify-between items-center">
<img src="@/assets/svg/Monitor/Triangle.svg" />
<span class="text-[2.03vh] youshe leading-none">手术量统计</span>
<section class="boxWrap">
<div class="opGradeBox box">
<header>
<div>
<p class="panmen">手术等级</p>
</div>
</header>
<main>
<div class="h-full" ref="echartsContainerLeft"></div>
</main>
</div>
<div class="w-[35.46vh] h-[28.05vh] ml-[2.4vh] opBody">
<div class="h-[30vh] w-full">
<Histogram v-if="getDataList.length" :getDataList="getDataList"></Histogram>
<div v-else class="flex flex-col w-[100%] h-[100%] items-center justify-center">
<img src="@/assets/img/noData.png" class="w-[120px]" />
<span>暂无数据</span>
<div class="asaGradeBox box">
<header>
<div>
<p class="panmen">ASA分级</p>
</div>
</div>
</header>
<main>
<div class="h-full" ref="echartsContainerRight"></div>
</main>
</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 class="opstatisticBox box">
<header>
<div>
<p class="panmen">科室手术量统计前五</p>
</div>
</header>
<main></main>
<section class="sidebar">
<div class="top" :class="{ 'active': active == 'week' }" @click="changeActive('week')">
<span></span>
</div>
<div class="bottom" :class="{ 'active': active == 'month' }" @click="changeActive('month')">
<span></span>
</div>
</section>
</div>
</div>
</section>
</template>
<script>
import { GetMonitorOperationNumber } from '@/api/monitor';
import * as echarts from 'echarts';
import { GetMonitorOperationLevel, GetMonitorOperationASALevel } from '@/api/monitor';
import { fnR } from '@/utils/common';
import dayjs from 'dayjs';
import Histogram from '@/views/pageMonitor/bottomLeft/OpHistogram.vue';
let chartLeft = null;
let chartRight = null;
export default {
data() {
return {
startDate: dayjs().subtract(7, 'day').format('YYYY-MM-DD'),
endDate: dayjs().format('YYYY-MM-DD'),
sliderClass: {
bgWeekBox: true,
bgMonthBox: false,
active: 'week',
nowIndex: 0,
chartOptionsLeft: {
series: [
{
type: 'pie',
radius: ['32%', '50%'],
selectedMode: 'single',
data: [
{ name: '一级', value: 148, selected: false },
{ name: '二级', value: 87, selected: false },
{ name: '三级', value: 75, selected: false },
{ name: '四级', value: 40, selected: false },
],
label: {
formatter: '{b}{c}',
color: 'inherit',
},
labelLine: {
show: true,
length: 15,
length2: 18,
smooth: 0.6, // 使线使
},
padAngle: 5,
itemStyle: {
borderRadius: 10,
},
},
{
name: '外边框-outBig',
type: 'pie',
clockWise: false, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['62%', '62%'],
label: {
normal: {
show: false,
},
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#2F58B4',
},
},
},
],
},
{
name: '外边框-outSmall',
type: 'pie',
clockWise: false, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['57%', '57%'],
label: {
normal: {
show: false,
},
},
showEmptyCircle: true,
itemStyle: {
shadowColor: 'rgba(255, 0, 0, 1)',
shadowBlur: 10,
opacity: 1,
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#0D447C',
},
},
},
],
},
{
name: '内边框-inBig',
type: 'pie',
clockWise: true, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['25%', '25%'],
label: {
normal: {
show: false,
},
},
itemStyle: {
shadowColor: 'rgba(255, 0, 0, 1)',
shadowBlur: 10,
opacity: 1,
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#006CFF',
opacity: 0.4,
},
},
},
],
},
{
name: '内边框-inSmall',
type: 'pie',
clockWise: true, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['20%', '20%'],
label: {
normal: {
show: false,
},
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#fff',
opacity: 0.2,
},
},
},
],
},
],
},
chartOptionsRight: {
series: [
{
type: 'pie',
radius: ['32%', '50%'],
selectedMode: 'single',
data: [
{ name: 'I级', value: 137, selected: false },
{ name: 'II级', value: 105, selected: false },
{ name: 'III级', value: 58, selected: false },
{ name: 'IV级', value: 37, selected: false },
{ name: 'V级', value: 13, selected: false },
],
label: {
formatter: '{b}{c}',
color: 'inherit',
},
labelLine: {
show: true,
length: 15,
length2: 18,
smooth: 0.6, // 使线使
},
padAngle: 5,
itemStyle: {
borderRadius: 10,
},
},
{
name: '外边框-outBig',
type: 'pie',
clockWise: false, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['62%', '62%'],
label: {
normal: {
show: false,
},
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#2F58B4',
},
},
},
],
},
{
name: '外边框-outSmall',
type: 'pie',
clockWise: false, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['57%', '57%'],
label: {
normal: {
show: false,
},
},
showEmptyCircle: true,
itemStyle: {
shadowColor: 'rgba(255, 0, 0, 1)',
shadowBlur: 10,
opacity: 1,
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#0D447C',
},
},
},
],
},
{
name: '内边框-inBig',
type: 'pie',
clockWise: true, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['25%', '25%'],
label: {
normal: {
show: false,
},
},
itemStyle: {
shadowColor: 'rgba(255, 0, 0, 1)',
shadowBlur: 10,
opacity: 1,
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#006CFF',
opacity: 0.4,
},
},
},
],
},
{
name: '内边框-inSmall',
type: 'pie',
clockWise: true, //
hoverAnimation: false, //
center: ['50%', '50%'],
radius: ['20%', '20%'],
label: {
normal: {
show: false,
},
},
data: [
{
value: 9,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#fff',
opacity: 0.2,
},
},
},
],
},
],
},
renderTimer: null,
isLoading: true,
getDataList: [],
toDate: dayjs().format('YYYY-MM-DD'),
};
},
components: {
Histogram,
},
methods: {
changeActive(newActive) {
this.active = newActive
},
onGetPageData() {
this.isLoading = true;
GetMonitorOperationNumber({
startDate: this.startDate,
endDate: this.endDate,
}).then(res => {
// this.getDataList = res["data"] || [];
// this.isLoading = false;
this.getDataList = [res['data']] || [];
Promise.all([GetMonitorOperationLevel(this.toDate), GetMonitorOperationASALevel(this.toDate)]).then(res => {
this.chartOptionsLeft.series[0].data[0].value = res[0].data['level1'];
this.chartOptionsLeft.series[0].data[1].value = res[0].data['level2'];
this.chartOptionsLeft.series[0].data[2].value = res[0].data['level3'];
this.chartOptionsLeft.series[0].data[3].value = res[0].data['level4'];
this.chartOptionsRight.series[0].data[0].value = res[1].data['asaLevel1'];
this.chartOptionsRight.series[0].data[1].value = res[1].data['asaLevel2'];
this.chartOptionsRight.series[0].data[2].value = res[1].data['asaLevel3'];
this.chartOptionsRight.series[0].data[3].value = res[1].data['asaLevel4'];
this.chartOptionsRight.series[0].data[4].value = res[1].data['asaLevel5'];
if (this.$store.getters.isMock) {
this.chartOptionsLeft.series[0].data[0].value = fnR();
this.chartOptionsLeft.series[0].data[1].value = fnR();
this.chartOptionsLeft.series[0].data[2].value = fnR();
this.chartOptionsLeft.series[0].data[3].value = fnR();
this.chartOptionsRight.series[0].data[0].value = fnR();
this.chartOptionsRight.series[0].data[1].value = fnR();
this.chartOptionsRight.series[0].data[2].value = fnR();
this.chartOptionsRight.series[0].data[3].value = fnR();
this.chartOptionsRight.series[0].data[4].value = fnR();
}
chartLeft.setOption(this.chartOptionsLeft);
chartRight.setOption(this.chartOptionsRight);
this.isLoading = false;
});
},
toWeek() {
this.startDate = dayjs().subtract(7, 'day').format('YYYY-MM-DD');
this.sliderClass.bgWeekBox = true;
this.sliderClass.bgMonthBox = false;
this.onGetPageData();
},
toMonth() {
this.startDate = dayjs().subtract(30, 'day').format('YYYY-MM-DD');
this.sliderClass.bgWeekBox = false;
this.sliderClass.bgMonthBox = true;
this.onGetPageData();
},
},
mounted() {
chartLeft = echarts.init(this.$refs.echartsContainerLeft);
chartLeft.setOption(this.chartOptionsLeft);
chartRight = echarts.init(this.$refs.echartsContainerRight);
chartRight.setOption(this.chartOptionsRight);
this.onGetPageData();
this.renderTimer = setInterval(() => {
if (this.sliderClass.bgWeekBox) {
this.toMonth();
} else {
this.toWeek();
}
setInterval(() => {
this.onGetPageData();
}, this.$store.getters.intervalTime);
},
beforeRouteLeave() {
clearInterval(this.renderTimer);
},
};
</script>
<style>
.bgBottomRightBox {
background-image: url('@/assets/svg/Monitor/BottomRight/Box.svg');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.bgWeekBox {
background-image: url('@/assets/svg/Monitor/BottomLeft/WeekActive.svg');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.bgMonthBox {
background-image: url('@/assets/svg/Monitor/BottomLeft/MonthActive.svg');
}
.opBody {
height: calc(100% - 5.07vh);
display: flex;
justify-content: center;
align-items: center;
}
<style lang="scss" scoped>
@import './index.scss'
</style>

@ -1,46 +1,27 @@
<template>
<div>
<div class="flex justify-evenly">
<topLeft></topLeft>
<topRight></topRight>
</div>
<div class="flex justify-evenly">
<bottomLeft></bottomLeft>
<div class="w-[116.94vh] flex justify-between">
<bottomMiddle></bottomMiddle>
<bottomRight></bottomRight>
</div>
</div>
</div>
<section class="flex justify-evenly items-center flex-wrap">
<topLeft />
<topRight />
<bottomLeft />
<bottomRight />
</section>
</template>
<script>
import topLeft from "./topLeft/index.vue";
import topRight from "./topRight/index.vue";
import bottomLeft from "./bottomLeft/index.vue";
import bottomMiddle from "./bottomMiddle/index.vue";
import bottomRight from './bottomRight/index.vue';
export default {
data() {
return {
isLoading: true,
topLeftData: {
firstPunctualityRate: 0,
roomUserRate: 0,
patEmergencyCount: 0,
patCount: 0,
patOperationing: 0,
patWating: 0,
},
};
}
},
components: {
topLeft,
topRight,
bottomLeft,
bottomMiddle,
bottomRight,
},
};

@ -0,0 +1,177 @@
.box {
width: vw(552);
height: vh(444);
box-sizing: border-box;
margin-bottom: vh(24);
border: 2px solid #DFE0F3;
box-shadow: 2px 4px 20px 0px rgba(87, 68, 175, 0.2);
background: linear-gradient(180deg, rgba(240, 243, 253, 0.95) 0%, rgba(232, 238, 253, 0.95) 100%);
border-radius: vw(8);
padding: vh(8) vw(8);
header {
height: vh(48);
background-image: url("@/assets/img/pageMonitor/headerLine.png");
background-size: contain;
background-repeat: no-repeat;
background-position: center bottom;
div {
width: vw(200);
height: vh(40);
background-image: url("@/assets/img/pageMonitor/headerBg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
margin-left: vw(12);
display: flex;
align-items: center;
p {
color: #444444;
font-size: vw(22);
padding-left: vw(32);
}
}
}
main {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: center;
height: vh(390);
.top {
width: vw(488);
height: vh(160);
display: flex;
justify-content: space-evenly;
align-items: center;
background: linear-gradient(180deg, #F2F3FA 0%, #EAE9FE 100%);
border: 1px solid #EDE9F4;
box-sizing: border-box;
border-radius: vw(4);
.left {
div:first-of-type {
display: flex;
align-items: center;
margin-bottom: vh(12);
min-width: vw(120);
img {
margin-right: vw(8);
}
span {
font-size: vw(20);
color: #302D32;
}
}
div:last-of-type {
color: #876395;
font-size: vw(24);
line-height: vw(44);
letter-spacing: 2px;
span {
color: #924AAC;
font-size: vw(44);
vertical-align: bottom;
}
}
}
.right {
.numBox {
width: vw(276);
height: vh(50);
background: linear-gradient(272deg, rgba(255, 85, 238, 0.045) 2%, rgba(150, 35, 135, 0.066) 99%);
border: 2px solid;
border-image: linear-gradient(161deg, rgba(255, 169, 205, 0.4) -11%, rgba(255, 169, 202, 0) 42%) 1.5;
box-sizing: border-box;
padding: 0 vw(16);
display: flex;
justify-content: space-between;
align-items: center;
.leftTextBox {
display: flex;
align-items: center;
.potionBox {
width: vw(4);
height: vw(4);
border-radius: 100%;
background: #D58DFF;
box-shadow: 0px 0px vw(4) vw(2) #D58DFF;
margin-right: vw(12);
}
span {
font-size: vw(16);
color: #571273;
}
}
.rightTextBox {
font-size: vw(14);
color: #571273;
line-height: vw(28);
span {
font-size: vw(28);
color: #924AAC;
vertical-align: bottom;
margin-right: vw(4);
}
}
&:first-of-type {
margin-bottom: vh(20);
}
}
}
}
.bottom {
width: vw(488);
height: vh(160);
display: flex;
justify-content: space-between;
div {
width: vw(146);
height: vh(160);
box-sizing: border-box;
padding: vh(24) vw(20);
background: linear-gradient(180deg, #F2F3FA 0%, #DEE6FF 100%);
border: 2px solid #EDE9F4;
border-radius: vw(4);
.secondRow {
margin-top: vh(12);
margin-bottom: vh(4);
font-size: vw(16);
color: #302D32;
}
.thridRow {
font-size: vw(28);
color: #605C68;
span {
font-size: vw(44);
color: #5D49AF;
margin-right: 2px;
}
}
}
}
}
}

@ -1,44 +1,49 @@
<template>
<div class="w-[51.29vh] h-[39.62vh] bgTopLeftBox bg-contain bg-center bg-no-repeat p-[3vh] box-border">
<section class="flex justify-between">
<template v-for="(item, index) in overviewData">
<div class="w-[12.96vh] h-[14.81vh] bgTopLeftItemBox bg-contain bg-no-repeat pl-[1.48vh] py-[0.92vh]" :key="index">
<img src="@/assets/svg/Monitor/TopLeft/TriangleBlue.svg" />
<p class="tracking-[0.27vh] text-[1.48vh] leading-none mt-[2vh] mb-[2vh] opacity-80">
{{ item['itemName'] }}
</p>
<p class="">
<span class="text-[4.25vh] youshe text-[#733FF3] leading-none">{{ item['itemVal'] }}</span>
<span class="text-[2.22vh] youshe text-[#733FF3] leading-none">{{ item['itemUnit'] }}</span>
</p>
</div>
</template>
</section>
<div class="w-[45.18vh] h-[14.81vh] bgTopLeftItemBoxPurple bg-contain bg-no-repeat mt-[3.7vh] px-[2.96vh] py-[2.4vh] flex justify-between items-center">
<section>
<div class="flex">
<img src="@/assets/svg/Monitor/TopLeft/TrianglePurple.svg" />
<span class="youshe text-[1.75vh] ml-[1.11vh] opacity-80">总人数</span>
<div class="box">
<header>
<div>
<p class="panmen">手术室换台情况</p>
</div>
</header>
<main>
<div class="top">
<div class="left">
<div>
<img src="@/assets/img/pageMonitor/triangle.png">
<span>总人数</span>
</div>
<div>
<span class="panmen">{{ totalPopulation }}</span>
</div>
</div>
<p class="text-[#B53FDF] text-[4.07vh] mt-[1.4vh] youshe leading-none">
{{ totalPopulation }}
</p>
</section>
<section>
<template v-for="(item, index) in peopleData">
<div class="w-[25.55vh] h-[4.07vh] peopleItemBox px-[2.22vh] flex justify-between items-center" :class="!index && 'mb-[1.85vh]'" :key="index">
<div class="flex items-end">
<img src="@/assets/svg/Monitor/TopLeft/PointPurple.svg" />
<span class="text-[1.48vh] opacity-80 ml-[0.74vh]">{{ item['itemName'] }}</span>
</div>
<div class="flex items-center">
<span class="text-[#B53FDF] text-[2.4vh] youshe">{{ item['itemVal'] }}</span>
<span class="text-[1.11vh] opacity-65 ml-[0.74vh]"></span>
<div class="right">
<template v-for="(item, index) in peopleData">
<div class="numBox" :key="index">
<div class="leftTextBox">
<div class="potionBox"></div>
<span>{{ item['itemName'] }}</span>
</div>
<div class="rightTextBox">
<span class="panmen">{{ item['itemVal'] }}</span>
</div>
</div>
</template>
</div>
</div>
<div class="bottom">
<template v-for="(item, index) in overviewData">
<div :key="index">
<img src="@/assets/img/pageMonitor/trianglePurple.png" />
<p class="secondRow">
{{ item['itemName'] }}
</p>
<p class="thridRow">
<span class="panmen">{{ item['itemVal'] }}</span>{{ item['itemUnit'] }}
</p>
</div>
</template>
</section>
</div>
</div>
</main>
</div>
</template>
@ -119,19 +124,6 @@ export default {
};
</script>
<style>
.bgTopLeftBox {
background-image: url('@/assets/svg/Monitor/TopLeft/Box.svg');
}
.bgTopLeftItemBox {
background-image: url('@/assets/svg/Monitor/TopLeft/ItemBox.svg');
}
.bgTopLeftItemBoxPurple {
background-image: url('@/assets/svg/Monitor/TopLeft/ItemBoxPurple.svg');
}
.peopleItemBox {
background: linear-gradient(271deg, rgba(85, 255, 212, 0.045) 2%, rgba(35, 150, 121, 0.066) 99%);
border: 1.5px solid;
border-image: linear-gradient(159deg, rgba(169, 213, 255, 0.4) -8%, rgba(169, 213, 255, 0) 38%) 1.5;
}
<style lang="scss" scoped>
@import './index.scss'
</style>

@ -0,0 +1,145 @@
.box {
width: vw(1280);
height: vh(444);
box-sizing: border-box;
margin-bottom: vh(24);
box-sizing: border-box;
border: 2px solid #DFE0F3;
box-shadow: 2px 4px 20px 0px rgba(87, 68, 175, 0.2);
background: linear-gradient(180deg, rgba(240, 243, 253, 0.95) 0%, rgba(232, 238, 253, 0.95) 100%);
border-radius: vw(8);
padding: vh(24);
position: relative;
}
:deep(.el-carousel) {
height: 100%;
.el-carousel__container {
height: 100%;
.el-carousel__item {
section {
height: 100%;
display: grid;
grid-template-columns: repeat(auto-fill, vw(186));
justify-content: space-between;
align-content: space-between;
>div {
height: vh(112);
box-sizing: border-box;
background: linear-gradient(180deg, rgba(232, 238, 255, 0.4) 0%, #E8EEFF 100%);
border: 2px solid #E3E5FD;
border-radius: vw(8);
p {
font-size: vw(22);
color: #000;
text-align: center;
letter-spacing: 2px;
line-height: vh(54);
}
.line {
height: 1px;
background: linear-gradient(90deg, rgba(0, 109, 171, 0) -1%, #A7DFFF 50%, rgba(0, 109, 171, 0) 98%);
}
div:last-of-type {
box-sizing: border-box;
height: vh(54);
padding: 0 vw(20);
display: flex;
align-items: center;
justify-content: space-evenly;
span {
color: #000;
font-size: vw(20);
letter-spacing: 1px;
}
}
&.opEnter {
p {
color: #35CEFD;
}
div:last-of-type {
span {
color: #35CEFD;
}
}
}
&.anesStart {
p {
color: #424CFE;
}
div:last-of-type {
span {
color: #424CFE;
}
}
}
&.opStart {
p {
color: #B53FDF;
}
div:last-of-type {
span {
color: #B53FDF;
}
}
}
&.opEnd {
p {
color: #BAE7A4;
}
div:last-of-type {
span {
color: #BAE7A4;
}
}
}
&.anesEnd {
p {
color: #946FEC;
}
div:last-of-type {
span {
color: #946FEC;
}
}
}
&.empty {
p {
color: #037E7E;
}
div:last-of-type {
span {
color: #037E7E;
}
}
}
}
}
}
}
}

@ -1,38 +1,17 @@
<template>
<div class="w-[116.94vh] h-[39.62vh] bgTopRightBox bg-contain bg-center bg-no-repeat p-[2.96vh] box-border">
<el-carousel direction="vertical" :autoplay="true" :interval="5000" indicatorPosition="none">
<div class="box">
<el-carousel direction="vertical" :autoplay="false" :interval="5000" indicatorPosition="none">
<el-carousel-item v-for="item in opList" :key="item['roomCode']">
<section>
<template v-for="(subItem, index) in item">
<div class="w-[12.59vh] h-[9.81vh] ItemBox relative" :key="index">
<p class="absolute w-[10.74vh] h-[2.77vh] leading--[2.77vh] text-[1.85vh] left-[0.92vh] top-[0.74vh] text-center youshe PBg">
<div :class="subItem['className']" :key="index">
<p class="panmen">
{{ subItem['roomName'] }}
</p>
<div class="absolute w-[10vh] h-[2.77vh] left-[1.03vh] bottom-[1.48vh]">
<div class="w-full h-full flex justify-between items-center" v-if="subItem.procStatus == 10">
<img src="@/assets/svg/Monitor/TopRight/opRoom.svg" class="relative top-[-2px]" />
<span class="text-[1.85vh] text-[#35CEFD] youshe text-nowrap">{{ subItem['operStatusName'] }}</span>
</div>
<div class="w-full h-full flex justify-between items-center" v-else-if="subItem.procStatus == 15">
<img src="@/assets/svg/Monitor/TopRight/anesStart.svg" class="relative top-[-2px]" />
<span class="text-[1.85vh] text-[#424CFE] youshe text-nowrap">{{ subItem['operStatusName'] }}</span>
</div>
<div class="w-full h-full flex justify-between items-center" v-else-if="subItem.procStatus == 20">
<img src="@/assets/svg/Monitor/TopRight/OpingIcon.svg" class="relative top-[-2px]" />
<span class="text-[1.85vh] text-[#B53FDF] youshe text-nowrap">{{ subItem['operStatusName'] }}</span>
</div>
<div class="w-full h-full flex justify-between items-center" v-else-if="subItem.procStatus == 25">
<img src="@/assets/svg/Monitor/TopRight/opEnd.svg" class="relative top-[-2px]" />
<span class="text-[1.85vh] text-[#BAE7A4] youshe text-nowrap">{{ subItem['operStatusName'] }}</span>
</div>
<div class="w-full h-full flex justify-between items-center" v-else-if="subItem.procStatus == 30">
<img src="@/assets/svg/Monitor/TopRight/OpendIcon.svg" class="relative top-[-2px]" />
<span class="text-[1.85vh] text-[#946FEC] youshe text-nowrap">{{ subItem['operStatusName'] }}</span>
</div>
<div class="w-full h-full flex justify-between items-center" v-else>
<img src="@/assets/svg/Monitor/TopRight/OpWaitIcon.svg" class="relative top-[-2px]" />
<span class="text-[1.85vh] text-[#0CFFFF] youshe text-nowrap">{{ subItem['operStatusName'] }}</span>
</div>
<div class="line"></div>
<div>
<img :src="subItem['iconUrl']" />
<span>{{ subItem['operStatusName'] }}</span>
</div>
</div>
</template>
@ -42,6 +21,7 @@
</div>
</template>
<script>
import { Carousel, CarouselItem } from 'element-ui';
import { GetMonitorOperationRoomStatus } from '@/api/monitor';
@ -50,26 +30,67 @@ export default {
data() {
return {
opList: [],
isLoading: true,
};
},
methods: {
onGetPageData() {
let nowDay = dayjs().format('YYYY-MM-DD');
if (this.$store.getters.isMock) {
nowDay = '2024-06-06';
nowDay = '2025-08-11';
}
GetMonitorOperationRoomStatus(nowDay).then(res => {
this.formatData(res['data']);
this.isLoading = false;
});
},
formatData(pageData) {
this.opList = [];
let group = 0;
for (let i = 0; i < pageData['length']; i++) {
group = parseInt(i / 21);
if (i % 6 == 0) {
pageData[i]['procStatus'] = 10;
pageData[i]['operStatusName'] = `入手术间`;
}
if (i % 6 == 1) {
pageData[i]['procStatus'] = 15;
pageData[i]['operStatusName'] = `麻醉开始`;
}
if (i % 6 == 2) {
pageData[i]['procStatus'] = 20;
pageData[i]['operStatusName'] = `手术开始`;
}
if (i % 6 == 3) {
pageData[i]['procStatus'] = 25;
pageData[i]['operStatusName'] = `手术结束`;
}
if (i % 6 == 4) {
pageData[i]['procStatus'] = 30;
pageData[i]['operStatusName'] = `麻醉结束`;
}
if (i % 6 == 5) {
pageData[i]['procStatus'] = 35;
pageData[i]['operStatusName'] = `空置中`;
}
if (pageData[i]['procStatus'] == 10) {
pageData[i]['className'] = `opEnter`
pageData[i]['iconUrl'] = require(`@/assets/svg/Monitor/TopRight/opRoom.svg`)
} else if (pageData[i]['procStatus'] == 15) {
pageData[i]['className'] = `anesStart`
pageData[i]['iconUrl'] = require(`@/assets/svg/Monitor/TopRight/anesStart.svg`)
} else if (pageData[i]['procStatus'] == 20) {
pageData[i]['className'] = `opStart`
pageData[i]['iconUrl'] = require(`@/assets/svg/Monitor/TopRight/OpingIcon.svg`)
} else if (pageData[i]['procStatus'] == 25) {
pageData[i]['className'] = `opEnd`
pageData[i]['iconUrl'] = require(`@/assets/svg/Monitor/TopRight/opEnd.svg`)
} else if (pageData[i]['procStatus'] == 30) {
pageData[i]['className'] = `anesEnd`
pageData[i]['iconUrl'] = require(`@/assets/svg/Monitor/TopRight/OpendIcon.svg`)
} else {
pageData[i]['className'] = `empty`
pageData[i]['iconUrl'] = require(`@/assets/svg/Monitor/TopRight/OpWaitIcon.svg`)
}
group = parseInt(i / 18);
if (this.opList[group]) {
this.opList[group].push(pageData[i]);
} else {
@ -80,9 +101,9 @@ export default {
},
mounted() {
this.onGetPageData();
setInterval(() => {
this.onGetPageData();
}, this.$store.getters.intervalTime);
// setInterval(() => {
// this.onGetPageData();
// }, this.$store.getters.intervalTime);
},
components: {
'el-carousel': Carousel,
@ -92,42 +113,5 @@ export default {
</script>
<style lang="scss" scoped>
.bgTopRightBox {
background-image: url('@/assets/svg/Monitor/TopRight/Box.svg');
:deep(.el-carousel) {
height: 39.62vh;
.el-carousel__container {
height: 39.62vh;
.el-carousel__item {
section {
display: grid;
grid-template-columns: repeat(7, minmax(12.59vh, 1fr));
gap: 3.7vh;
grid-row-gap: 1.85vh;
}
}
}
}
}
.ItemBox {
background-image: url('@/assets/svg/Monitor/TopRight/ItemBox.svg');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.PBg {
background: linear-gradient(90deg, rgba(0, 147, 255, 0) 0%, rgba(0, 147, 255, 0.37) 44%, rgba(0, 147, 255, 0) 99%);
position: relative;
&::after {
content: '';
display: block;
width: 100%;
height: 1px;
position: absolute;
bottom: 0;
left: 0;
background: linear-gradient(90deg, rgba(0, 147, 255, 0) 0%, #0093ff 49%, rgba(0, 147, 255, 0) 99%);
}
}
@import './index.scss'
</style>

@ -1,4 +1,11 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
transpileDependencies: true,
css: {
loaderOptions: {
scss: {
additionalData: `@import "@/assets/scss/utils.scss";`
}
}
}
})

Loading…
Cancel
Save