refactor(map): branchOffice 所有统计页 按块拆分
parent
66d5d27fb8
commit
7b2f826b63
|
|
@ -40,7 +40,7 @@
|
|||
"react-transition-group": "^4.4.5",
|
||||
"sass": "^1.97.0",
|
||||
"sass-loader": "^16.0.6",
|
||||
"zy-react-library": "^2.0.13"
|
||||
"zy-react-library": "^2.0.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^5.4.1",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
import CountUp from "react-countup";
|
||||
import areaIcon from "~/assets/images/map_bi/content/icon29.png";
|
||||
import quayIcon from "~/assets/images/map_bi/content/icon30.png";
|
||||
import cornerIcon from "~/assets/images/map_bi/content/icon32.png";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const statistics = [
|
||||
{ img: areaIcon, title: "堆场区", peopleCount: 123, vehicleCount: 45 },
|
||||
{ img: quayIcon, title: "码头区", peopleCount: 141, vehicleCount: 43 },
|
||||
];
|
||||
|
||||
/** 负责展示封闭区域内的人员和车辆统计。 */
|
||||
function ClosedAreaStatsPanel() {
|
||||
return (
|
||||
<Panel title="封闭区域统计">
|
||||
<div className="branch-office-closed-area-stats__content">
|
||||
{statistics.map(item => (
|
||||
<div
|
||||
className="branch-office-closed-area-stats__item"
|
||||
key={item.title}
|
||||
>
|
||||
<div className="branch-office-closed-area-stats__image">
|
||||
<img src={item.img} alt="" />
|
||||
</div>
|
||||
<div className="branch-office-closed-area-stats__info">
|
||||
<div className="branch-office-closed-area-stats__title">
|
||||
{item.title}
|
||||
</div>
|
||||
<div className="branch-office-closed-area-stats__values">
|
||||
<Statistic label="人数" value={item.peopleCount} />
|
||||
<Statistic label="车辆数" value={item.vehicleCount} />
|
||||
</div>
|
||||
</div>
|
||||
<Corner className="branch-office-closed-area-stats__corner--top-left" />
|
||||
<Corner className="branch-office-closed-area-stats__corner--top-right" />
|
||||
<Corner className="branch-office-closed-area-stats__corner--bottom-left" />
|
||||
<Corner className="branch-office-closed-area-stats__corner--bottom-right" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
/** 封闭区域统计项的单个数值展示。 */
|
||||
function Statistic({ label, value }) {
|
||||
return (
|
||||
<div>
|
||||
<div className="branch-office-closed-area-stats__label">{label}</div>
|
||||
<div className="branch-office-closed-area-stats__value">
|
||||
<CountUp end={+value} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** 区域卡片四角的装饰图标。 */
|
||||
function Corner({ className }) {
|
||||
return (
|
||||
<div className={`branch-office-closed-area-stats__corner ${className}`}>
|
||||
<img src={cornerIcon} alt="" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ClosedAreaStatsPanel;
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
.branch-office-closed-area-stats__content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px 6px;
|
||||
justify-content: space-between;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-basis: calc(50% - 10px);
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
background-color: rgba(1, 56, 154, 0.5);
|
||||
border: 1px solid rgba(32, 145, 243, 0.36);
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__image img {
|
||||
width: 57px;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__info {
|
||||
margin-left: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__title {
|
||||
color: #0096ff;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__values {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__corner {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__corner--top-left {
|
||||
top: -9px;
|
||||
left: -4px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__corner--top-right {
|
||||
top: -4px;
|
||||
right: -9px;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__corner--bottom-left {
|
||||
bottom: -4px;
|
||||
left: -9px;
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.branch-office-closed-area-stats__corner--bottom-right {
|
||||
right: -4px;
|
||||
bottom: -9px;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import { useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const tabs = ["人员", "车辆"];
|
||||
const records = [
|
||||
{ NAME: "零号门", IN: "0", OUT: "0" },
|
||||
{ NAME: "一号门", IN: "15", OUT: "12" },
|
||||
{ NAME: "二号门", IN: "8", OUT: "10" },
|
||||
{ NAME: "三号门", IN: "22", OUT: "18" },
|
||||
{ NAME: "四号门", IN: "5", OUT: "7" },
|
||||
{ NAME: "五号门", IN: "30", OUT: "25" },
|
||||
{ NAME: "六号门", IN: "12", OUT: "14" },
|
||||
{ NAME: "七号门", IN: "18", OUT: "16" },
|
||||
{ NAME: "八号门", IN: "9", OUT: "11" },
|
||||
{ NAME: "九号门", IN: "25", OUT: "20" },
|
||||
];
|
||||
|
||||
/** 负责展示封闭区域进出记录及分类标签状态。 */
|
||||
function EntryExitRecordPanel() {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title="封闭区域进出情况统计"
|
||||
className="branch-office-closed-area__record"
|
||||
extra={(
|
||||
<div className="branch-office-closed-area-record__tabs">
|
||||
{tabs.map((item, index) => (
|
||||
<div
|
||||
className={`branch-office-closed-area-record__tab ${index === activeIndex ? "branch-office-closed-area-record__tab--active" : ""}`}
|
||||
key={item}
|
||||
onClick={() => setActiveIndex(index)}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className="branch-office-closed-area-record__content">
|
||||
<div className="branch-office-closed-area-record__table">
|
||||
<div className="branch-office-closed-area-record__row">
|
||||
<div>封闭区域名称</div>
|
||||
<div>进入数</div>
|
||||
<div>外出数</div>
|
||||
</div>
|
||||
<div className="branch-office-closed-area-record__body">
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div
|
||||
className="branch-office-closed-area-record__row"
|
||||
key={index}
|
||||
>
|
||||
<div>{item.NAME}</div>
|
||||
<div>{item.IN}</div>
|
||||
<div>{item.OUT}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default EntryExitRecordPanel;
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
.branch-office-closed-area__record {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-record__tabs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-record__tab {
|
||||
padding: 2px 12px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
background-color: rgba(36, 115, 239, 0.27);
|
||||
border: 1px solid #5d718c;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-record__tab--active {
|
||||
background-color: #2473ef;
|
||||
border-color: #2473ef;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-record__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-record__body {
|
||||
height: 350px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-record__row {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr 1fr;
|
||||
background-color: rgba(42, 86, 158, 0.53);
|
||||
}
|
||||
|
||||
.branch-office-closed-area-record__body
|
||||
.branch-office-closed-area-record__row:nth-child(odd) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-record__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
import { useMount } from "ahooks";
|
||||
import * as echarts from "echarts";
|
||||
import { useRef, useState } from "react";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const tabs = ["人员", "车辆"];
|
||||
const records = [
|
||||
{ NAME: "零号门", IN: "0", OUT: "0" },
|
||||
{ NAME: "一号门", IN: "15", OUT: "12" },
|
||||
{ NAME: "二号门", IN: "8", OUT: "10" },
|
||||
{ NAME: "三号门", IN: "22", OUT: "18" },
|
||||
{ NAME: "四号门", IN: "5", OUT: "7" },
|
||||
{ NAME: "五号门", IN: "30", OUT: "25" },
|
||||
{ NAME: "六号门", IN: "12", OUT: "14" },
|
||||
{ NAME: "七号门", IN: "18", OUT: "16" },
|
||||
{ NAME: "八号门", IN: "9", OUT: "11" },
|
||||
{ NAME: "九号门", IN: "25", OUT: "20" },
|
||||
];
|
||||
|
||||
/** 负责展示封闭区域进出趋势并管理图表实例生命周期。 */
|
||||
function EntryExitTrendPanel() {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const chartInstance = useRef(null);
|
||||
const chartRef = useRef(null);
|
||||
|
||||
const initEcharts = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const inData = data.map(item => Number.parseInt(item.IN));
|
||||
const outData = data.map(item => Number.parseInt(item.OUT));
|
||||
const names = data.map(item => item.NAME);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "none",
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ["进", "出"],
|
||||
top: "0%",
|
||||
right: "0%",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 14,
|
||||
},
|
||||
itemWidth: 12,
|
||||
itemHeight: 10,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: "7%",
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 5,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
grid: {
|
||||
left: "10%",
|
||||
right: "5%",
|
||||
top: "10%",
|
||||
bottom: "20%",
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
data: names,
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "进",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(121,103,255,0.7)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#7967FF",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: inData,
|
||||
},
|
||||
{
|
||||
name: "出",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(255,198,124,0.7)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#FFC67C",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: outData,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
||||
useMount(() => {
|
||||
initEcharts(chartRef, chartInstance, records);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title="封闭区域进出情况统计"
|
||||
className="branch-office-closed-area__trend"
|
||||
extra={(
|
||||
<div className="branch-office-closed-area-trend__tabs">
|
||||
{tabs.map((item, index) => (
|
||||
<div
|
||||
className={`branch-office-closed-area-trend__tab ${index === activeIndex ? "branch-office-closed-area-trend__tab--active" : ""}`}
|
||||
key={item}
|
||||
onClick={() => setActiveIndex(index)}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className="branch-office-closed-area-trend__content">
|
||||
<div
|
||||
ref={chartRef}
|
||||
className="branch-office-closed-area-trend__chart"
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default EntryExitTrendPanel;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
.branch-office-closed-area__trend {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-trend__tabs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-trend__tab {
|
||||
padding: 2px 12px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
background-color: rgba(36, 115, 239, 0.27);
|
||||
border: 1px solid #5d718c;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-trend__tab--active {
|
||||
background-color: #2473ef;
|
||||
border-color: #2473ef;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-trend__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-trend__chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
import * as echarts from "echarts";
|
||||
|
||||
export const initEcharts1 = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const inData = data.map(item => Number.parseInt(item.IN));
|
||||
const outData = data.map(item => Number.parseInt(item.OUT));
|
||||
const names = data.map(item => item.NAME);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "none",
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ["进", "出"],
|
||||
top: "0%",
|
||||
right: "0%",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 14,
|
||||
},
|
||||
itemWidth: 12,
|
||||
itemHeight: 10,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: "7%",
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 5,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
grid: {
|
||||
left: "10%",
|
||||
right: "5%",
|
||||
top: "10%",
|
||||
bottom: "20%",
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
data: names,
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "进",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(121,103,255,0.7)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#7967FF",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: inData,
|
||||
},
|
||||
{
|
||||
name: "出",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(255,198,124,0.7)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#FFC67C",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: outData,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
|
@ -1,178 +1,14 @@
|
|||
import { useMount } from "ahooks";
|
||||
import { useRef, useState } from "react";
|
||||
import CountUp from "react-countup";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import icon29 from "~/assets/images/map_bi/content/icon29.png";
|
||||
import icon30 from "~/assets/images/map_bi/content/icon30.png";
|
||||
import icon32 from "~/assets/images/map_bi/content/icon32.png";
|
||||
import Title from "~/pages/Container/Map/components/Content/branchOffice/Title";
|
||||
import { initEcharts1 } from "./echarts";
|
||||
import "./index.less";
|
||||
|
||||
const block2OptionsNavList = ["人员", "车辆"];
|
||||
const block3OptionsNavList = ["人员", "车辆"];
|
||||
import ClosedAreaStatsPanel from "./ClosedAreaStatsPanel";
|
||||
import EntryExitRecordPanel from "./EntryExitRecordPanel";
|
||||
import EntryExitTrendPanel from "./EntryExitTrendPanel";
|
||||
|
||||
/** 分公司封闭区域模块仅负责按展示顺序组合业务区块。 */
|
||||
function FengBi() {
|
||||
const [block1List, setBlock1List] = useState([
|
||||
{ img: icon29, title: "堆场区", count1: 123, count2: 45 },
|
||||
{ img: icon30, title: "码头区", count1: 141, count2: 43 },
|
||||
]);
|
||||
const [block2Index, setBlock2Index] = useState(0);
|
||||
const [block3Index, setBlock3Index] = useState(0);
|
||||
const [block3List, setBlock3List] = useState([
|
||||
{ NAME: "零号门", IN: "0", OUT: "0" },
|
||||
{ NAME: "一号门", IN: "15", OUT: "12" },
|
||||
{ NAME: "二号门", IN: "8", OUT: "10" },
|
||||
{ NAME: "三号门", IN: "22", OUT: "18" },
|
||||
{ NAME: "四号门", IN: "5", OUT: "7" },
|
||||
{ NAME: "五号门", IN: "30", OUT: "25" },
|
||||
{ NAME: "六号门", IN: "12", OUT: "14" },
|
||||
{ NAME: "七号门", IN: "18", OUT: "16" },
|
||||
{ NAME: "八号门", IN: "9", OUT: "11" },
|
||||
{ NAME: "九号门", IN: "25", OUT: "20" },
|
||||
]);
|
||||
|
||||
const chartInstance = useRef(null);
|
||||
const main1Ref = useRef(null);
|
||||
|
||||
useMount(() => {
|
||||
initEcharts1(main1Ref, chartInstance, [
|
||||
{ NAME: "零号门", IN: "0", OUT: "0" },
|
||||
{ NAME: "一号门", IN: "15", OUT: "12" },
|
||||
{ NAME: "二号门", IN: "8", OUT: "10" },
|
||||
{ NAME: "三号门", IN: "22", OUT: "18" },
|
||||
{ NAME: "四号门", IN: "5", OUT: "7" },
|
||||
{ NAME: "五号门", IN: "30", OUT: "25" },
|
||||
{ NAME: "六号门", IN: "12", OUT: "14" },
|
||||
{ NAME: "七号门", IN: "18", OUT: "16" },
|
||||
{ NAME: "八号门", IN: "9", OUT: "11" },
|
||||
{ NAME: "九号门", IN: "25", OUT: "20" },
|
||||
]);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const block2OptionsClick = (index) => {
|
||||
if (index === block2Index)
|
||||
return;
|
||||
setBlock2Index(index);
|
||||
};
|
||||
|
||||
const block3OptionsClick = (index) => {
|
||||
if (index === block3Index)
|
||||
return;
|
||||
setBlock3Index(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="branch_office_fengbi">
|
||||
<div className="block1">
|
||||
<Title title="封闭区域统计" />
|
||||
<div className="options">
|
||||
{
|
||||
block1List.map((item, index) => (
|
||||
<div className="option" key={index}>
|
||||
<div className="img">
|
||||
<img src={item.img} alt="" />
|
||||
</div>
|
||||
<div className="infos">
|
||||
<div className="title">{item.title}</div>
|
||||
<div className="info">
|
||||
<div>
|
||||
<div className="label">人数</div>
|
||||
<div className="value">
|
||||
<CountUp end={+item.count1}></CountUp>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="label">车辆数</div>
|
||||
<div className="value">
|
||||
<CountUp end={+item.count2}></CountUp>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="corner-img top-left-img">
|
||||
<img src={icon32} alt="" />
|
||||
</div>
|
||||
<div className="corner-img top-right-img">
|
||||
<img src={icon32} alt="" />
|
||||
</div>
|
||||
<div className="corner-img bottom-left-img">
|
||||
<img src={icon32} alt="" />
|
||||
</div>
|
||||
<div className="corner-img bottom-right-img">
|
||||
<img src={icon32} alt="" />
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className="block2">
|
||||
<Title
|
||||
title="封闭区域进出情况统计"
|
||||
extra={(
|
||||
<div className="tabs">
|
||||
{block2OptionsNavList.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`tab ${index === block2Index ? "active" : ""}`}
|
||||
onClick={() => block2OptionsClick(index)}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<div className="options">
|
||||
<div ref={main1Ref} style={{ width: "100%", height: "300px" }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="block3">
|
||||
<Title
|
||||
title="封闭区域进出情况统计"
|
||||
extra={(
|
||||
<div className="tabs">
|
||||
{block3OptionsNavList.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`tab ${index === block3Index ? "active" : ""}`}
|
||||
onClick={() => block3OptionsClick(index)}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<div className="options">
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">封闭区域名称</div>
|
||||
<div className="td">进入数</div>
|
||||
<div className="td">外出数</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={block3List} step={0.5}>
|
||||
{block3List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.NAME}</div>
|
||||
<div className="td">{item.IN}</div>
|
||||
<div className="td">{item.OUT}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-closed-area">
|
||||
<ClosedAreaStatsPanel />
|
||||
<EntryExitTrendPanel />
|
||||
<EntryExitRecordPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,175 +0,0 @@
|
|||
.branch_office_fengbi {
|
||||
.tabs-style() {
|
||||
display: flex;
|
||||
|
||||
.tab {
|
||||
background-color: rgba(36, 115, 239, 0.27);
|
||||
padding: 2px 12px;
|
||||
border-radius: 2px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
border: 1px solid #5d718c;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
background-color: #2473ef;
|
||||
border: 1px solid #2473ef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block1 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px 6px;
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
|
||||
.option {
|
||||
flex-basis: calc(50% - 10px);
|
||||
background-color: rgba(1, 56, 154, 0.5);
|
||||
border: 1px solid rgba(32, 145, 243, 0.36);
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
|
||||
.img {
|
||||
img {
|
||||
width: 57px;
|
||||
height: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
.infos {
|
||||
margin-left: 20px;
|
||||
text-align: center;
|
||||
|
||||
.title {
|
||||
color: #0096FF;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.corner-img {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
|
||||
&.top-left-img {
|
||||
top: -9px;
|
||||
left: -4px;
|
||||
}
|
||||
|
||||
&.top-right-img {
|
||||
transform: rotate(90deg);
|
||||
top: -4px;
|
||||
right: -9px;
|
||||
}
|
||||
|
||||
&.bottom-left-img {
|
||||
transform: rotate(270deg);
|
||||
bottom: -4px;
|
||||
left: -9px;
|
||||
}
|
||||
|
||||
&.bottom-right-img {
|
||||
transform: rotate(180deg);
|
||||
bottom: -9px;
|
||||
right: -4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block2 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.tabs {
|
||||
.tabs-style();
|
||||
}
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.block3 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.tabs {
|
||||
.tabs-style();
|
||||
}
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.table {
|
||||
.scroll {
|
||||
height: 350px;
|
||||
overflow-y: hidden;
|
||||
|
||||
.tr {
|
||||
&:nth-child(odd) {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tr {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr 1fr;
|
||||
background-color: rgba(42, 86, 158, 0.53);
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
|
||||
&.green {
|
||||
color: #7ccf41;
|
||||
}
|
||||
|
||||
&.yellow {
|
||||
color: #ffcb05;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
import { useMount } from "ahooks";
|
||||
import * as echarts from "echarts";
|
||||
import { useRef } from "react";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{
|
||||
departmentName: "技术部",
|
||||
riskCoverageRate: 95,
|
||||
hiddenInvestigationRate: 92,
|
||||
hiddenRectificationRate: 90,
|
||||
checkTaskCompletionRate: 94,
|
||||
},
|
||||
{
|
||||
departmentName: "销售部",
|
||||
riskCoverageRate: 88,
|
||||
hiddenInvestigationRate: 85,
|
||||
hiddenRectificationRate: 87,
|
||||
checkTaskCompletionRate: 89,
|
||||
},
|
||||
{
|
||||
departmentName: "市场部",
|
||||
riskCoverageRate: 92,
|
||||
hiddenInvestigationRate: 90,
|
||||
hiddenRectificationRate: 88,
|
||||
checkTaskCompletionRate: 91,
|
||||
},
|
||||
{
|
||||
departmentName: "运营部",
|
||||
riskCoverageRate: 96,
|
||||
hiddenInvestigationRate: 94,
|
||||
hiddenRectificationRate: 95,
|
||||
checkTaskCompletionRate: 93,
|
||||
},
|
||||
{
|
||||
departmentName: "客服部",
|
||||
riskCoverageRate: 85,
|
||||
hiddenInvestigationRate: 83,
|
||||
hiddenRectificationRate: 86,
|
||||
checkTaskCompletionRate: 84,
|
||||
},
|
||||
{
|
||||
departmentName: "财务部",
|
||||
riskCoverageRate: 98,
|
||||
hiddenInvestigationRate: 96,
|
||||
hiddenRectificationRate: 97,
|
||||
checkTaskCompletionRate: 97,
|
||||
},
|
||||
{
|
||||
departmentName: "人事部",
|
||||
riskCoverageRate: 87,
|
||||
hiddenInvestigationRate: 84,
|
||||
hiddenRectificationRate: 85,
|
||||
checkTaskCompletionRate: 86,
|
||||
},
|
||||
{
|
||||
departmentName: "研发部",
|
||||
riskCoverageRate: 94,
|
||||
hiddenInvestigationRate: 91,
|
||||
hiddenRectificationRate: 93,
|
||||
checkTaskCompletionRate: 92,
|
||||
},
|
||||
{
|
||||
departmentName: "质量部",
|
||||
riskCoverageRate: 90,
|
||||
hiddenInvestigationRate: 88,
|
||||
hiddenRectificationRate: 89,
|
||||
checkTaskCompletionRate: 88,
|
||||
},
|
||||
{
|
||||
departmentName: "采购部",
|
||||
riskCoverageRate: 86,
|
||||
hiddenInvestigationRate: 84,
|
||||
hiddenRectificationRate: 83,
|
||||
checkTaskCompletionRate: 85,
|
||||
},
|
||||
];
|
||||
|
||||
/** 负责展示部门职责落实趋势,并管理图表实例生命周期。 */
|
||||
function DepartmentResponsibilityPanel() {
|
||||
const chartInstance = useRef(null);
|
||||
const chartRef = useRef(null);
|
||||
|
||||
const initEcharts = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const option = {
|
||||
color: ["#7d4449", "#009944", "#167ce4", "#00ffff"],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
},
|
||||
legend: {
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: "12px",
|
||||
},
|
||||
top: 8,
|
||||
right: 10,
|
||||
},
|
||||
grid: {
|
||||
left: "4%",
|
||||
right: "4%",
|
||||
bottom: "10%",
|
||||
top: "26%",
|
||||
containLabel: true,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: 0,
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 3,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
xAxis: {
|
||||
data: data.map(item => item.departmentName),
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
symbol: "none",
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
color: "#fff",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
fontSize: 12,
|
||||
padding: [0, 10, 0, 0],
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: "rgba(255,255,255,0.79)",
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "风险点检查覆盖率",
|
||||
type: "line",
|
||||
data: data.map(item => item.riskCoverageRate),
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
showSymbol: false,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
},
|
||||
{
|
||||
name: "隐患清单排查率",
|
||||
data: data.map(item => item.hiddenInvestigationRate),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
showSymbol: false,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
},
|
||||
{
|
||||
name: "隐崽整改率",
|
||||
data: data.map(item => item.hiddenRectificationRate),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
showSymbol: false,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
},
|
||||
{
|
||||
name: "检查任务完成率",
|
||||
data: data.map(item => item.checkTaskCompletionRate),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
showSymbol: false,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
||||
useMount(() => {
|
||||
initEcharts(chartRef, chartInstance, records);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title="部门职责落实情况"
|
||||
className="branch-office-index-left__responsibility"
|
||||
>
|
||||
<div className="branch-office-department-responsibility__content">
|
||||
<div
|
||||
ref={chartRef}
|
||||
className="branch-office-department-responsibility__chart"
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default DepartmentResponsibilityPanel;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.branch-office-index-left__responsibility {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-department-responsibility__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-department-responsibility__chart {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{
|
||||
relatedPartyCategory: "承包商",
|
||||
firstLevelUnits: 15,
|
||||
firstLevelPersonnel: 120,
|
||||
secondLevelUnits: 25,
|
||||
secondLevelPersonnel: 320,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "供应商",
|
||||
firstLevelUnits: 8,
|
||||
firstLevelPersonnel: 85,
|
||||
secondLevelUnits: 18,
|
||||
secondLevelPersonnel: 210,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "分包商",
|
||||
firstLevelUnits: 12,
|
||||
firstLevelPersonnel: 95,
|
||||
secondLevelUnits: 30,
|
||||
secondLevelPersonnel: 450,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "监理单位",
|
||||
firstLevelUnits: 5,
|
||||
firstLevelPersonnel: 40,
|
||||
secondLevelUnits: 10,
|
||||
secondLevelPersonnel: 80,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "设计单位",
|
||||
firstLevelUnits: 6,
|
||||
firstLevelPersonnel: 55,
|
||||
secondLevelUnits: 12,
|
||||
secondLevelPersonnel: 120,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "施工单位",
|
||||
firstLevelUnits: 18,
|
||||
firstLevelPersonnel: 200,
|
||||
secondLevelUnits: 40,
|
||||
secondLevelPersonnel: 680,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "检测机构",
|
||||
firstLevelUnits: 3,
|
||||
firstLevelPersonnel: 25,
|
||||
secondLevelUnits: 8,
|
||||
secondLevelPersonnel: 65,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "咨询公司",
|
||||
firstLevelUnits: 7,
|
||||
firstLevelPersonnel: 60,
|
||||
secondLevelUnits: 15,
|
||||
secondLevelPersonnel: 180,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "运维单位",
|
||||
firstLevelUnits: 9,
|
||||
firstLevelPersonnel: 75,
|
||||
secondLevelUnits: 22,
|
||||
secondLevelPersonnel: 320,
|
||||
},
|
||||
{
|
||||
relatedPartyCategory: "其他单位",
|
||||
firstLevelUnits: 4,
|
||||
firstLevelPersonnel: 35,
|
||||
secondLevelUnits: 14,
|
||||
secondLevelPersonnel: 150,
|
||||
},
|
||||
];
|
||||
|
||||
/** 负责展示相关方单位及其人员统计。 */
|
||||
function RelatedPartyStatsPanel() {
|
||||
return (
|
||||
<Panel
|
||||
title="相关方单位统计"
|
||||
className="branch-office-index-left__related-party"
|
||||
>
|
||||
<div className="branch-office-related-party-stats__content">
|
||||
<div className="branch-office-related-party-stats__table">
|
||||
<div className="branch-office-related-party-stats__row">
|
||||
<div>相关方类别</div>
|
||||
<div>一级单位数</div>
|
||||
<div>一级人数</div>
|
||||
<div>二级单位数</div>
|
||||
<div>二级人数</div>
|
||||
</div>
|
||||
<div className="branch-office-related-party-stats__body">
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div
|
||||
className="branch-office-related-party-stats__row"
|
||||
key={index}
|
||||
>
|
||||
<div>{item.relatedPartyCategory}</div>
|
||||
<div>{item.firstLevelUnits}</div>
|
||||
<div>{item.firstLevelPersonnel}</div>
|
||||
<div>{item.secondLevelUnits}</div>
|
||||
<div>{item.secondLevelPersonnel}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default RelatedPartyStatsPanel;
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
.branch-office-index-left__related-party {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-related-party-stats__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-related-party-stats__table {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-office-related-party-stats__body {
|
||||
height: 60px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-related-party-stats__row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;
|
||||
margin-top: 5px;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
}
|
||||
|
||||
.branch-office-related-party-stats__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ levelName: "重大风险", riskCount: 21, notRiskCount: 3 },
|
||||
{ levelName: "较大风险", riskCount: 21, notRiskCount: 3 },
|
||||
{ levelName: "一般风险", riskCount: 21, notRiskCount: 3 },
|
||||
{ levelName: "低风险", riskCount: 21, notRiskCount: 3 },
|
||||
];
|
||||
|
||||
const levelColor = {
|
||||
重大风险: "#ff0000",
|
||||
较大风险: "#ff3c00",
|
||||
一般风险: "#e5e72f",
|
||||
低风险: "#0e7dfa",
|
||||
};
|
||||
|
||||
/** 负责展示不同风险等级的风险点与隐患覆盖情况。 */
|
||||
function RiskHazardPanel() {
|
||||
return (
|
||||
<Panel title="风险点隐患" className="branch-office-index-left__risk-hazard">
|
||||
<div className="branch-office-risk-hazard__content">
|
||||
{records.map((item) => {
|
||||
const color = levelColor[item.levelName];
|
||||
return (
|
||||
<div
|
||||
className="branch-office-risk-hazard__item"
|
||||
key={item.levelName}
|
||||
>
|
||||
<div
|
||||
className="branch-office-risk-hazard__decoration"
|
||||
style={{ backgroundColor: color }}
|
||||
/>
|
||||
<div
|
||||
className="branch-office-risk-hazard__title"
|
||||
style={{ color, borderColor: color }}
|
||||
>
|
||||
{item.levelName}
|
||||
</div>
|
||||
<div className="branch-office-risk-hazard__info">
|
||||
<div>
|
||||
风险点数:
|
||||
{item.riskCount}
|
||||
</div>
|
||||
<div className="branch-office-risk-hazard__details">
|
||||
<div>检查覆盖率:100%</div>
|
||||
<div>
|
||||
未覆盖风险点数:
|
||||
{item.notRiskCount}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default RiskHazardPanel;
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
.branch-office-index-left__risk-hazard {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-risk-hazard__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-risk-hazard__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 19px;
|
||||
align-items: center;
|
||||
padding: 6px 10px;
|
||||
margin-top: 5px;
|
||||
background-color: rgba(1, 37, 74, 0.47);
|
||||
border: 1px solid rgba(0, 168, 255, 0.36);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.branch-office-risk-hazard__item:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.branch-office-risk-hazard__decoration {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
height: 15px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.branch-office-risk-hazard__title {
|
||||
flex-basis: 85px;
|
||||
padding: 10px 7px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.branch-office-risk-hazard__info {
|
||||
flex: 1;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.branch-office-risk-hazard__details {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { Spin } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import temperatureIcon from "~/assets/images/public/bigScreen/img10.png";
|
||||
import windIcon from "~/assets/images/public/bigScreen/img11.png";
|
||||
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import { getAlertColor, getWeatherIcon } from "~/utils/weather";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ department: "技术部", requiredDevices: 150, anchoredDevices: 142 },
|
||||
{ department: "销售部", requiredDevices: 80, anchoredDevices: 76 },
|
||||
{ department: "市场部", requiredDevices: 60, anchoredDevices: 58 },
|
||||
{ department: "运营部", requiredDevices: 120, anchoredDevices: 115 },
|
||||
{ department: "客服部", requiredDevices: 90, anchoredDevices: 88 },
|
||||
{ department: "财务部", requiredDevices: 30, anchoredDevices: 29 },
|
||||
{ department: "人事部", requiredDevices: 25, anchoredDevices: 24 },
|
||||
{ department: "研发部", requiredDevices: 200, anchoredDevices: 195 },
|
||||
{ department: "质量部", requiredDevices: 45, anchoredDevices: 42 },
|
||||
{ department: "采购部", requiredDevices: 35, anchoredDevices: 33 },
|
||||
];
|
||||
|
||||
/** 负责查询并展示天气、预警和部门设备锚定情况。 */
|
||||
function WeatherPreventionPanel(props) {
|
||||
const [weather, setWeather] = useState({});
|
||||
const [alerts, setAlerts] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadWeather = async () => {
|
||||
const { result = {} } = await props.getWeather();
|
||||
setWeather(result.now || {});
|
||||
setAlerts(Array.isArray(result.alerts) ? result.alerts : []);
|
||||
};
|
||||
loadWeather();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Panel title="天气预防情况">
|
||||
<Spin spinning={props.biStatistics.getWeatherLoading}>
|
||||
<div className="branch-office-weather-prevention__content">
|
||||
<div className="branch-office-weather-prevention__weather">
|
||||
<div className="branch-office-weather-prevention__condition">
|
||||
<div className="branch-office-weather-prevention__condition-image">
|
||||
<img src={getWeatherIcon(weather.text)} alt="" />
|
||||
</div>
|
||||
<div className="branch-office-weather-prevention__condition-text">
|
||||
{weather.text || "暂无"}
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-weather-prevention__metrics">
|
||||
<WeatherMetric
|
||||
icon={temperatureIcon}
|
||||
label="温度:"
|
||||
value={weather.temp ? `${weather.temp}℃` : "--"}
|
||||
/>
|
||||
<WeatherMetric
|
||||
icon={windIcon}
|
||||
label="风速:"
|
||||
value={weather.wind_class || "--"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-weather-prevention__alerts">
|
||||
<SeamlessScroll
|
||||
list={alerts}
|
||||
step={0.5}
|
||||
limitScrollNum={2}
|
||||
singleHeight={22}
|
||||
>
|
||||
{alerts.map((item, index) => (
|
||||
<div
|
||||
className="branch-office-weather-prevention__alert"
|
||||
key={index}
|
||||
style={{ color: getAlertColor(item.level) }}
|
||||
>
|
||||
{item.title}
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
<DepartmentTable records={records} />
|
||||
</div>
|
||||
</Spin>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
/** 天气区块中的单个基础指标。 */
|
||||
function WeatherMetric({ icon, label, value }) {
|
||||
return (
|
||||
<div className="branch-office-weather-prevention__metric">
|
||||
<img src={icon} alt="" />
|
||||
<div>
|
||||
<div className="branch-office-weather-prevention__metric-label">
|
||||
{label}
|
||||
</div>
|
||||
<div className="branch-office-weather-prevention__metric-value">
|
||||
{value}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** 天气预防区块内的部门设备锚定列表。 */
|
||||
function DepartmentTable({ records }) {
|
||||
return (
|
||||
<div className="branch-office-weather-prevention__table">
|
||||
<div className="branch-office-weather-prevention__row">
|
||||
<div>部门名称</div>
|
||||
<div>需锚定设备数</div>
|
||||
<div>已锚定设备数</div>
|
||||
</div>
|
||||
<div className="branch-office-weather-prevention__table-body">
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div className="branch-office-weather-prevention__row" key={index}>
|
||||
<div>{item.department}</div>
|
||||
<div>{item.requiredDevices}</div>
|
||||
<div>{item.anchoredDevices}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_BI_STATISTICS], true)(WeatherPreventionPanel);
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
.branch-office-weather-prevention__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__weather {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__condition {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__condition-image img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__condition-text {
|
||||
color: #fff;
|
||||
letter-spacing: 5px;
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__metrics {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__metric {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__metric img {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__metric-label {
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__metric-value {
|
||||
color: #00e7ff;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__alerts {
|
||||
height: 20px;
|
||||
margin-top: 10px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__alert {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__table {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__table-body {
|
||||
height: 60px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
margin-top: 5px;
|
||||
background-image: linear-gradient(to bottom,
|
||||
rgba(0, 42, 85, 0.38),
|
||||
rgba(1, 37, 74, 0.47),
|
||||
rgba(4, 38, 87, 0));
|
||||
border: 1px solid;
|
||||
border-bottom: none;
|
||||
border-image: linear-gradient(to top,
|
||||
rgba(8, 41, 87, 0.5),
|
||||
rgba(64, 152, 255, 0.5)) 1;
|
||||
}
|
||||
|
||||
.branch-office-weather-prevention__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
import * as echarts from "echarts";
|
||||
|
||||
export const initEcharts1 = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const option = {
|
||||
color: ["#7d4449", "#009944", "#167ce4", "#00ffff"],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
},
|
||||
legend: {
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: "12px",
|
||||
},
|
||||
top: 8,
|
||||
right: 10,
|
||||
},
|
||||
grid: {
|
||||
left: "4%",
|
||||
right: "4%",
|
||||
bottom: "10%",
|
||||
top: "26%",
|
||||
containLabel: true,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: 0,
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 3,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
xAxis: {
|
||||
data: data.map(item => item.departmentName),
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
symbol: "none",
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
color: "#fff",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
fontSize: 12,
|
||||
padding: [0, 10, 0, 0],
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: "rgba(255,255,255,0.79)",
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "风险点检查覆盖率",
|
||||
type: "line",
|
||||
data: data.map(item => item.riskCoverageRate),
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
showSymbol: false,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
},
|
||||
{
|
||||
name: "隐患清单排查率",
|
||||
data: data.map(item => item.hiddenInvestigationRate),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
showSymbol: false,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
},
|
||||
{
|
||||
name: "隐崽整改率",
|
||||
data: data.map(item => item.hiddenRectificationRate),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
showSymbol: false,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
},
|
||||
{
|
||||
name: "检查任务完成率",
|
||||
data: data.map(item => item.checkTaskCompletionRate),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
showSymbol: false,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
|
@ -1,220 +1,18 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { useMount } from "ahooks";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import icon1 from "~/assets/images/public/bigScreen/img10.png";
|
||||
import icon2 from "~/assets/images/public/bigScreen/img11.png";
|
||||
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
|
||||
import Title from "~/pages/Container/Map/components/Content/branchOffice/Title";
|
||||
import { getAlertColor, getWeatherIcon } from "~/utils/weather";
|
||||
import { initEcharts1 } from "./echarts";
|
||||
import "./index.less";
|
||||
|
||||
function IndexLeft(props) {
|
||||
const [weatherData, setWeatherData] = useState({});
|
||||
const [alert, setAlert] = useState([]);
|
||||
const [block1List, setBlock1List] = useState([
|
||||
{ department: "技术部", requiredDevices: 150, anchoredDevices: 142 },
|
||||
{ department: "销售部", requiredDevices: 80, anchoredDevices: 76 },
|
||||
{ department: "市场部", requiredDevices: 60, anchoredDevices: 58 },
|
||||
{ department: "运营部", requiredDevices: 120, anchoredDevices: 115 },
|
||||
{ department: "客服部", requiredDevices: 90, anchoredDevices: 88 },
|
||||
{ department: "财务部", requiredDevices: 30, anchoredDevices: 29 },
|
||||
{ department: "人事部", requiredDevices: 25, anchoredDevices: 24 },
|
||||
{ department: "研发部", requiredDevices: 200, anchoredDevices: 195 },
|
||||
{ department: "质量部", requiredDevices: 45, anchoredDevices: 42 },
|
||||
{ department: "采购部", requiredDevices: 35, anchoredDevices: 33 },
|
||||
]);
|
||||
const [block2List, setBlock2List] = useState([
|
||||
{ levelName: "重大风险", riskCount: 21, notRiskCount: 3 },
|
||||
{ levelName: "较大风险", riskCount: 21, notRiskCount: 3 },
|
||||
{ levelName: "一般风险", riskCount: 21, notRiskCount: 3 },
|
||||
{ levelName: "低风险", riskCount: 21, notRiskCount: 3 },
|
||||
]);
|
||||
const [block4List, setBlock4List] = useState([
|
||||
{ relatedPartyCategory: "承包商", firstLevelUnits: 15, firstLevelPersonnel: 120, secondLevelUnits: 25, secondLevelPersonnel: 320 },
|
||||
{ relatedPartyCategory: "供应商", firstLevelUnits: 8, firstLevelPersonnel: 85, secondLevelUnits: 18, secondLevelPersonnel: 210 },
|
||||
{ relatedPartyCategory: "分包商", firstLevelUnits: 12, firstLevelPersonnel: 95, secondLevelUnits: 30, secondLevelPersonnel: 450 },
|
||||
{ relatedPartyCategory: "监理单位", firstLevelUnits: 5, firstLevelPersonnel: 40, secondLevelUnits: 10, secondLevelPersonnel: 80 },
|
||||
{ relatedPartyCategory: "设计单位", firstLevelUnits: 6, firstLevelPersonnel: 55, secondLevelUnits: 12, secondLevelPersonnel: 120 },
|
||||
{ relatedPartyCategory: "施工单位", firstLevelUnits: 18, firstLevelPersonnel: 200, secondLevelUnits: 40, secondLevelPersonnel: 680 },
|
||||
{ relatedPartyCategory: "检测机构", firstLevelUnits: 3, firstLevelPersonnel: 25, secondLevelUnits: 8, secondLevelPersonnel: 65 },
|
||||
{ relatedPartyCategory: "咨询公司", firstLevelUnits: 7, firstLevelPersonnel: 60, secondLevelUnits: 15, secondLevelPersonnel: 180 },
|
||||
{ relatedPartyCategory: "运维单位", firstLevelUnits: 9, firstLevelPersonnel: 75, secondLevelUnits: 22, secondLevelPersonnel: 320 },
|
||||
{ relatedPartyCategory: "其他单位", firstLevelUnits: 4, firstLevelPersonnel: 35, secondLevelUnits: 14, secondLevelPersonnel: 150 },
|
||||
]);
|
||||
|
||||
const chartInstance = useRef(null);
|
||||
const main1Ref = useRef(null);
|
||||
|
||||
const getWeatherData = async () => {
|
||||
const { result = {} } = await props.getWeather();
|
||||
setWeatherData(result.now);
|
||||
setAlert(Array.isArray(result.alerts) ? result.alerts : []);
|
||||
};
|
||||
|
||||
const getLevelColor = (level) => {
|
||||
return { 重大风险: "#FF0000", 较大风险: "#FF3C00", 一般风险: "#E5E72F", 低风险: "#0E7DFA" }[level];
|
||||
};
|
||||
|
||||
useMount(() => {
|
||||
initEcharts1(main1Ref, chartInstance, [
|
||||
{ departmentName: "技术部", riskCoverageRate: 95, hiddenInvestigationRate: 92, hiddenRectificationRate: 90, checkTaskCompletionRate: 94 },
|
||||
{ departmentName: "销售部", riskCoverageRate: 88, hiddenInvestigationRate: 85, hiddenRectificationRate: 87, checkTaskCompletionRate: 89 },
|
||||
{ departmentName: "市场部", riskCoverageRate: 92, hiddenInvestigationRate: 90, hiddenRectificationRate: 88, checkTaskCompletionRate: 91 },
|
||||
{ departmentName: "运营部", riskCoverageRate: 96, hiddenInvestigationRate: 94, hiddenRectificationRate: 95, checkTaskCompletionRate: 93 },
|
||||
{ departmentName: "客服部", riskCoverageRate: 85, hiddenInvestigationRate: 83, hiddenRectificationRate: 86, checkTaskCompletionRate: 84 },
|
||||
{ departmentName: "财务部", riskCoverageRate: 98, hiddenInvestigationRate: 96, hiddenRectificationRate: 97, checkTaskCompletionRate: 97 },
|
||||
{ departmentName: "人事部", riskCoverageRate: 87, hiddenInvestigationRate: 84, hiddenRectificationRate: 85, checkTaskCompletionRate: 86 },
|
||||
{ departmentName: "研发部", riskCoverageRate: 94, hiddenInvestigationRate: 91, hiddenRectificationRate: 93, checkTaskCompletionRate: 92 },
|
||||
{ departmentName: "质量部", riskCoverageRate: 90, hiddenInvestigationRate: 88, hiddenRectificationRate: 89, checkTaskCompletionRate: 88 },
|
||||
{ departmentName: "采购部", riskCoverageRate: 86, hiddenInvestigationRate: 84, hiddenRectificationRate: 83, checkTaskCompletionRate: 85 },
|
||||
]);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
getWeatherData();
|
||||
}, []);
|
||||
import DepartmentResponsibilityPanel from "./DepartmentResponsibilityPanel";
|
||||
import RelatedPartyStatsPanel from "./RelatedPartyStatsPanel";
|
||||
import RiskHazardPanel from "./RiskHazardPanel";
|
||||
import WeatherPreventionPanel from "./WeatherPreventionPanel";
|
||||
|
||||
/** 分公司首页左侧区域仅负责按展示顺序组合业务区块。 */
|
||||
function IndexLeft() {
|
||||
return (
|
||||
<div className="branch_office_index_left">
|
||||
<div className="block1">
|
||||
<Title title="天气预防情况" />
|
||||
<div className="options">
|
||||
<div className="weather">
|
||||
<div className="icon">
|
||||
<div className="img">
|
||||
<img src={getWeatherIcon(weatherData.text)} alt="" />
|
||||
</div>
|
||||
<div className="text">{weatherData.text || "暂无"}</div>
|
||||
</div>
|
||||
<div className="items">
|
||||
<div className="item">
|
||||
<div className="img">
|
||||
<img src={icon1} alt="" />
|
||||
</div>
|
||||
<div className="info">
|
||||
<div className="label">温度:</div>
|
||||
<div className="value">{weatherData.temp ? `${weatherData.temp}℃` : "--"}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="item">
|
||||
<div className="img">
|
||||
<img src={icon2} alt="" />
|
||||
</div>
|
||||
<div className="info">
|
||||
<div className="label">风速:</div>
|
||||
<div className="value">{weatherData.wind_class || "--"}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="alert">
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={alert} step={0.5} limitScrollNum={2} singleHeight={22}>
|
||||
{
|
||||
alert.map((item, index) => (
|
||||
<div className="item" key={index}>
|
||||
<div className="title" style={{ color: getAlertColor(item.level) }}>{item.title}</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">部门名称</div>
|
||||
<div className="td">需锚定设备数</div>
|
||||
<div className="td">已锚定设备数</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={block1List} step={0.5}>
|
||||
{block1List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.department}</div>
|
||||
<div className="td">{item.requiredDevices}</div>
|
||||
<div className="td">{item.anchoredDevices}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="block2">
|
||||
<Title title="风险点隐患" />
|
||||
<div className="options">
|
||||
<div className="items">
|
||||
{block2List.map((item, index) => (
|
||||
<div className="item" key={index}>
|
||||
<div className="decoration" style={{ backgroundColor: getLevelColor(item.levelName) }} />
|
||||
<div className="title" style={{ color: getLevelColor(item.levelName), borderColor: getLevelColor(item.levelName) }}>
|
||||
{item.levelName}
|
||||
</div>
|
||||
<div className="info">
|
||||
<div>
|
||||
<span>风险点数:</span>
|
||||
<span>{item.riskCount}</span>
|
||||
</div>
|
||||
<div className="bottom">
|
||||
<div>
|
||||
<span>检查覆盖率:</span>
|
||||
<span>{`${(item.riskCount / item.riskCount * 100).toFixed(0)}%`}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>未覆盖风险点数:</span>
|
||||
<span>{item.notRiskCount}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="block3">
|
||||
<Title title="部门职责落实情况" />
|
||||
<div className="options">
|
||||
<div ref={main1Ref} style={{ width: "100%", height: "200px" }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="block4">
|
||||
<Title title="相关方单位统计" />
|
||||
<div className="options">
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">相关方类别</div>
|
||||
<div className="td">一级单位数</div>
|
||||
<div className="td">一级人数</div>
|
||||
<div className="td">二级单位数</div>
|
||||
<div className="td">二级人数</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={block4List} step={0.5}>
|
||||
{block4List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.relatedPartyCategory}</div>
|
||||
<div className="td">{item.firstLevelUnits}</div>
|
||||
<div className="td">{item.firstLevelPersonnel}</div>
|
||||
<div className="td">{item.secondLevelUnits}</div>
|
||||
<div className="td">{item.secondLevelPersonnel}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-index-left">
|
||||
<WeatherPreventionPanel />
|
||||
<RiskHazardPanel />
|
||||
<DepartmentResponsibilityPanel />
|
||||
<RelatedPartyStatsPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_BI_STATISTICS], true)(IndexLeft);
|
||||
export default IndexLeft;
|
||||
|
|
|
|||
|
|
@ -1,229 +0,0 @@
|
|||
.branch_office_index_left {
|
||||
.block1 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.weather {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 40px;
|
||||
|
||||
.icon {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
|
||||
.img {
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
color: #fff;
|
||||
writing-mode: vertical-lr;
|
||||
letter-spacing: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.img {
|
||||
img {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
.label {
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 18px;
|
||||
color: #00e7ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alert {
|
||||
margin-top: 10px;
|
||||
|
||||
.scroll {
|
||||
height: 20px;
|
||||
overflow-y: hidden;
|
||||
|
||||
.item {
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
margin-top: 5px;
|
||||
|
||||
.scroll {
|
||||
height: 60px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tr {
|
||||
margin-top: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
background-image: linear-gradient(to bottom, rgba(0, 42, 85, 0.38), rgba(1, 37, 74, 0.47), rgba(4, 38, 87, 0));
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to top, rgba(8, 41, 87, 0.5), rgba(64, 152, 255, 0.5)) 1;
|
||||
border-bottom: none;
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block2 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.items {
|
||||
.item {
|
||||
position: relative;
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 19px;
|
||||
border: 1px solid rgba(0, 168, 255, 0.36);
|
||||
background-color: rgba(1, 37, 74, 0.47);
|
||||
border-radius: 4px;
|
||||
padding: 6px 10px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.decoration {
|
||||
width: 2px;
|
||||
height: 15px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.title {
|
||||
border-radius: 4px;
|
||||
padding: 10px 7px;
|
||||
font-weight: bold;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
flex-basis: 85px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block3 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.block4 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.table {
|
||||
margin-top: 5px;
|
||||
|
||||
.scroll {
|
||||
height: 60px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tr {
|
||||
margin-top: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { Spin } from "antd";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import { Context } from "~/pages/Container/Map/js/context";
|
||||
import "./index.less";
|
||||
|
||||
const disposalStatus = { 10: "报警中", 20: "未处置", 30: "已消警" };
|
||||
|
||||
/** 负责查询并滚动展示封闭区域告警。 */
|
||||
function AreaAlarmPanel(props) {
|
||||
const { portArea, currentBranchOffice } = useContext(Context);
|
||||
const [records, setRecords] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadRecords = async () => {
|
||||
const { data = [] } = await props.getAlarmRecordScreenIotDeviceAlarmPage({
|
||||
portArea,
|
||||
corpinfoId: currentBranchOffice,
|
||||
pageIndex: 1,
|
||||
pageSize: 9999,
|
||||
});
|
||||
setRecords(data);
|
||||
};
|
||||
loadRecords();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Panel title="区域告警" className="branch-office-index-right__area-alarm">
|
||||
<div className="branch-office-area-alarm__content">
|
||||
<div className="branch-office-area-alarm__table">
|
||||
<div className="branch-office-area-alarm__row">
|
||||
<div>区域名称</div>
|
||||
<div>告警类型</div>
|
||||
<div>告警时间</div>
|
||||
<div>处置状态</div>
|
||||
</div>
|
||||
<div className="branch-office-area-alarm__body">
|
||||
<Spin
|
||||
spinning={
|
||||
props.biStatistics.getAlarmRecordScreenIotDeviceAlarmPageLoading
|
||||
}
|
||||
>
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div className="branch-office-area-alarm__row" key={index}>
|
||||
<div>{item.fireRegionName}</div>
|
||||
<div>{item.alarmTypeName}</div>
|
||||
<div>{item.alarmTime}</div>
|
||||
<div>{disposalStatus[item.status]}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</Spin>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_BI_STATISTICS], true)(AreaAlarmPanel);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
.branch-office-index-right__area-alarm {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-area-alarm__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-area-alarm__table {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-office-area-alarm__body {
|
||||
height: 165px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-area-alarm__row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr 2fr 1fr;
|
||||
margin-top: 5px;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
}
|
||||
|
||||
.branch-office-area-alarm__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
import { useMount } from "ahooks";
|
||||
import * as echarts from "echarts";
|
||||
import { useRef } from "react";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ name: "技术部1", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部2", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部3", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部4", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部5", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部6", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部7", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部8", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部9", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部0", unitCount: 95, personnelCount: 92 },
|
||||
];
|
||||
|
||||
/** 负责展示封闭区域人员状态图表,并管理图表实例生命周期。 */
|
||||
function ClosedAreaPersonnelPanel() {
|
||||
const chartInstance = useRef(null);
|
||||
const chartRef = useRef(null);
|
||||
|
||||
const initEcharts = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const option = {
|
||||
color: ["#F1C416", "#0AFCFF"],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
label: {
|
||||
backgroundColor: "#6a7985",
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
left: "1%",
|
||||
right: "4%",
|
||||
bottom: "6%",
|
||||
top: 30,
|
||||
padding: "0 0 10 0",
|
||||
containLabel: true,
|
||||
},
|
||||
legend: {
|
||||
right: 10,
|
||||
top: 0,
|
||||
itemGap: 16,
|
||||
itemWidth: 18,
|
||||
itemHeight: 10,
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontStyle: "normal",
|
||||
fontFamily: "微软雅黑",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: 0,
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 3,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
boundaryGap: true,
|
||||
data: data.map(item => item.name),
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
margin: 15,
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontStyle: "normal",
|
||||
fontFamily: "微软雅黑",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
opacity: 0.2,
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
splitNumber: 5,
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontStyle: "normal",
|
||||
fontFamily: "微软雅黑",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: ["#fff"],
|
||||
opacity: 0.06,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "单位人员数",
|
||||
type: "pictorialBar",
|
||||
symbol: "roundRect",
|
||||
symbolOffset: [-5, 0],
|
||||
symbolMargin: "1",
|
||||
barWidth: "10%",
|
||||
barMaxWidth: "20%",
|
||||
animationDelay: (dataIndex, params) => {
|
||||
return params.index * 50;
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: () => {
|
||||
return new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: "#F1C416",
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "#FF2F01",
|
||||
},
|
||||
]);
|
||||
},
|
||||
},
|
||||
},
|
||||
z: 1,
|
||||
barGap: 0,
|
||||
symbolRepeat: true,
|
||||
symbolSize: [14, 5],
|
||||
data: data.map(item => item.unitCount),
|
||||
animationEasing: "elasticOut",
|
||||
stack: "2",
|
||||
},
|
||||
{
|
||||
name: "相关方人员数",
|
||||
type: "pictorialBar",
|
||||
symbol: "roundRect",
|
||||
barWidth: "10%",
|
||||
symbolOffset: [5, 0],
|
||||
barMaxWidth: "20%",
|
||||
symbolMargin: "1",
|
||||
animationDelay: (dataIndex, params) => {
|
||||
return params.index * 50;
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: () => {
|
||||
return new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: "#0AFCFF",
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "#0CA1FE",
|
||||
},
|
||||
]);
|
||||
},
|
||||
},
|
||||
},
|
||||
z: 1,
|
||||
barGap: 0,
|
||||
symbolRepeat: true,
|
||||
symbolSize: [14, 5],
|
||||
data: data.map(item => item.personnelCount),
|
||||
animationEasing: "elasticOut",
|
||||
stack: "1",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
||||
useMount(() => {
|
||||
initEcharts(chartRef, chartInstance, records);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title="封闭区域人员状态"
|
||||
className="branch-office-index-right__personnel"
|
||||
>
|
||||
<div className="branch-office-closed-area-personnel__content">
|
||||
<div
|
||||
ref={chartRef}
|
||||
className="branch-office-closed-area-personnel__chart"
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default ClosedAreaPersonnelPanel;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.branch-office-index-right__personnel {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-personnel__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-closed-area-personnel__chart {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
import gateBackground from "~/assets/images/map_bi/content/bg4.png";
|
||||
import areaBackground from "~/assets/images/map_bi/content/bg5.png";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{
|
||||
title: "口门进出统计",
|
||||
label1: "人数",
|
||||
label2: "车数",
|
||||
count1: 123,
|
||||
count2: 123,
|
||||
background: gateBackground,
|
||||
},
|
||||
{
|
||||
title: "进入申请待审批",
|
||||
label1: "人数",
|
||||
label2: "车数",
|
||||
count1: 123,
|
||||
count2: 123,
|
||||
background: gateBackground,
|
||||
},
|
||||
{
|
||||
title: "封闭区域人员情况",
|
||||
label1: "区域数",
|
||||
label2: "人数",
|
||||
count1: 123,
|
||||
count2: 123,
|
||||
background: areaBackground,
|
||||
},
|
||||
{
|
||||
title: "封闭区域作业情况",
|
||||
label1: "区域数",
|
||||
label2: "作业数",
|
||||
count1: 123,
|
||||
count2: 123,
|
||||
background: areaBackground,
|
||||
},
|
||||
];
|
||||
|
||||
/** 负责展示口门和封闭区域的基础统计。 */
|
||||
function GateAndClosedAreaPanel() {
|
||||
return (
|
||||
<Panel title="口门及封闭区域">
|
||||
<div className="branch-office-gate-closed-area__content">
|
||||
{records.map(item => (
|
||||
<div
|
||||
className="branch-office-gate-closed-area__item"
|
||||
key={item.title}
|
||||
style={{ backgroundImage: `url(${item.background})` }}
|
||||
>
|
||||
<div className="branch-office-gate-closed-area__title">
|
||||
{item.title}
|
||||
</div>
|
||||
<div className="branch-office-gate-closed-area__values">
|
||||
<div>
|
||||
{item.label1}
|
||||
:
|
||||
{item.count1}
|
||||
</div>
|
||||
<div>
|
||||
{item.label2}
|
||||
:
|
||||
{item.count2}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default GateAndClosedAreaPanel;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
.branch-office-gate-closed-area__content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px 20px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 15px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.branch-office-gate-closed-area__item {
|
||||
width: calc(50% - 10px);
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
.branch-office-gate-closed-area__title {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.branch-office-gate-closed-area__values {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { Spin } from "antd";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import { Context } from "~/pages/Container/Map/js/context";
|
||||
import "./index.less";
|
||||
|
||||
/** 负责合并两类作业统计并展示部门维度数据。 */
|
||||
function KeyWorkStatsPanel(props) {
|
||||
const { portArea, currentBranchOffice } = useContext(Context);
|
||||
const [records, setRecords] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadRecords = async () => {
|
||||
const [{ data: eightWorkData = [] }, { data: keyProjectData = [] }]
|
||||
= await Promise.all([
|
||||
props.getEightWorkInfoScreenDepartmentStatistics({
|
||||
portArea,
|
||||
corpinfoId: currentBranchOffice,
|
||||
}),
|
||||
props.getKeyProjectLargeScreenDepartmentStatistics({
|
||||
portArea,
|
||||
corpinfoId: currentBranchOffice,
|
||||
}),
|
||||
]);
|
||||
const departmentMap = new Map(
|
||||
keyProjectData.map(item => [
|
||||
item.departmentId,
|
||||
{
|
||||
departmentName: item.departmentName,
|
||||
fourNewHomeworkCount: item.fourNewHomeworkCount,
|
||||
eightWorkCount: 0,
|
||||
morePeopleCount: item.morePeopleCount,
|
||||
},
|
||||
]),
|
||||
);
|
||||
eightWorkData.forEach((item) => {
|
||||
const department = departmentMap.get(item.departmentId) || {
|
||||
departmentName: item.departmentName,
|
||||
fourNewHomeworkCount: 0,
|
||||
eightWorkCount: 0,
|
||||
morePeopleCount: 0,
|
||||
};
|
||||
department.eightWorkCount = item.workCount || 0;
|
||||
departmentMap.set(item.departmentId, department);
|
||||
});
|
||||
setRecords([...departmentMap.values()]);
|
||||
};
|
||||
loadRecords();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title="重点作业情况统计"
|
||||
className="branch-office-index-right__key-work"
|
||||
>
|
||||
<div className="branch-office-key-work-stats__content">
|
||||
<div className="branch-office-key-work-stats__table">
|
||||
<div className="branch-office-key-work-stats__row">
|
||||
<div>部门名称</div>
|
||||
<div>三人以上作业数</div>
|
||||
<div>危险作业数</div>
|
||||
<div>四新作业数</div>
|
||||
</div>
|
||||
<div className="branch-office-key-work-stats__body">
|
||||
<Spin
|
||||
spinning={
|
||||
props.biStatistics
|
||||
.getKeyProjectLargeScreenDepartmentStatisticsLoading
|
||||
|| props.biStatistics
|
||||
.getEightWorkInfoScreenDepartmentStatisticsLoading
|
||||
}
|
||||
>
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div
|
||||
className="branch-office-key-work-stats__row"
|
||||
key={index}
|
||||
>
|
||||
<div>{item.departmentName}</div>
|
||||
<div>{item.morePeopleCount}</div>
|
||||
<div>{item.eightWorkCount}</div>
|
||||
<div>{item.fourNewHomeworkCount}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</Spin>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_BI_STATISTICS], true)(KeyWorkStatsPanel);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
.branch-office-index-right__key-work {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-key-work-stats__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-key-work-stats__table {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-office-key-work-stats__body {
|
||||
height: 165px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-key-work-stats__row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
margin-top: 5px;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
}
|
||||
|
||||
.branch-office-key-work-stats__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
import * as echarts from "echarts";
|
||||
|
||||
export const initEcharts1 = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const option = {
|
||||
color: ["#F1C416", "#0AFCFF"],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
label: {
|
||||
backgroundColor: "#6a7985",
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
left: "1%",
|
||||
right: "4%",
|
||||
bottom: "6%",
|
||||
top: 30,
|
||||
padding: "0 0 10 0",
|
||||
containLabel: true,
|
||||
},
|
||||
legend: {
|
||||
right: 10,
|
||||
top: 0,
|
||||
itemGap: 16,
|
||||
itemWidth: 18,
|
||||
itemHeight: 10,
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontStyle: "normal",
|
||||
fontFamily: "微软雅黑",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: 0,
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 3,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
boundaryGap: true,
|
||||
data: data.map(item => item.name),
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
margin: 15,
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontStyle: "normal",
|
||||
fontFamily: "微软雅黑",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
opacity: 0.2,
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
splitNumber: 5,
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontStyle: "normal",
|
||||
fontFamily: "微软雅黑",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: ["#fff"],
|
||||
opacity: 0.06,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "单位人员数",
|
||||
type: "pictorialBar",
|
||||
symbol: "roundRect",
|
||||
symbolOffset: [-5, 0],
|
||||
symbolMargin: "1",
|
||||
barWidth: "10%",
|
||||
barMaxWidth: "20%",
|
||||
animationDelay: (dataIndex, params) => {
|
||||
return params.index * 50;
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: () => {
|
||||
return new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: "#F1C416",
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "#FF2F01",
|
||||
},
|
||||
]);
|
||||
},
|
||||
},
|
||||
},
|
||||
z: 1,
|
||||
barGap: 0,
|
||||
symbolRepeat: true,
|
||||
symbolSize: [14, 5],
|
||||
data: data.map(item => item.unitCount),
|
||||
animationEasing: "elasticOut",
|
||||
stack: "2",
|
||||
},
|
||||
{
|
||||
name: "相关方人员数",
|
||||
type: "pictorialBar",
|
||||
symbol: "roundRect",
|
||||
barWidth: "10%",
|
||||
symbolOffset: [5, 0],
|
||||
barMaxWidth: "20%",
|
||||
symbolMargin: "1",
|
||||
animationDelay: (dataIndex, params) => {
|
||||
return params.index * 50;
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: (params) => {
|
||||
return new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: "#0AFCFF",
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "#0CA1FE",
|
||||
},
|
||||
]);
|
||||
},
|
||||
},
|
||||
},
|
||||
z: 1,
|
||||
barGap: 0,
|
||||
symbolRepeat: true,
|
||||
symbolSize: [14, 5],
|
||||
data: data.map(item => item.personnelCount),
|
||||
animationEasing: "elasticOut",
|
||||
stack: "1",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
|
@ -1,194 +1,18 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { useMount } from "ahooks";
|
||||
import { Spin } from "antd";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import bg4 from "~/assets/images/map_bi/content/bg4.png";
|
||||
import bg5 from "~/assets/images/map_bi/content/bg5.png";
|
||||
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
|
||||
import Title from "~/pages/Container/Map/components/Content/branchOffice/Title";
|
||||
import { Context } from "~/pages/Container/Map/js/context";
|
||||
import { initEcharts1 } from "./echarts";
|
||||
import "./index.less";
|
||||
|
||||
function IndexRight(props) {
|
||||
const { portArea, currentBranchOffice } = useContext(Context);
|
||||
|
||||
const [block1List, setBlock1List] = useState([
|
||||
{ title: "口门进出统计", label1: "人数", label2: "车数", count1: 123, count2: 123, bgImg: bg4 },
|
||||
{ title: "进入申请待审批", label1: "人数", label2: "车数", count1: 123, count2: 123, bgImg: bg4 },
|
||||
{ title: "封闭区域人员情况", label1: "区域数", label2: "人数", count1: 123, count2: 123, bgImg: bg5 },
|
||||
{ title: "封闭区域作业情况", label1: "区域数", label2: "作业数", count1: 123, count2: 123, bgImg: bg5 },
|
||||
]);
|
||||
const [block3List, setBlock3List] = useState([]);
|
||||
const [block4List, setBlock4List] = useState([]);
|
||||
|
||||
const chartInstance = useRef(null);
|
||||
const main1Ref = useRef(null);
|
||||
|
||||
useMount(() => {
|
||||
initEcharts1(main1Ref, chartInstance, [
|
||||
{ name: "技术部1", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部2", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部3", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部4", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部5", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部6", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部7", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部8", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部9", unitCount: 95, personnelCount: 92 },
|
||||
{ name: "技术部0", unitCount: 95, personnelCount: 92 },
|
||||
]);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const getAlarmRecordScreenIotDeviceAlarmPage = async () => {
|
||||
const { data } = await props.getAlarmRecordScreenIotDeviceAlarmPage({
|
||||
portArea,
|
||||
corpinfoId: currentBranchOffice,
|
||||
pageIndex: 1,
|
||||
pageSize: 9999,
|
||||
});
|
||||
setBlock3List(data);
|
||||
};
|
||||
|
||||
const getBlock4List = async () => {
|
||||
const [{ data: eightWorkData = [] }, { data: keyProjectData = [] }]
|
||||
= await Promise.all([
|
||||
props.getEightWorkInfoScreenDepartmentStatistics({
|
||||
portArea,
|
||||
corpinfoId: currentBranchOffice,
|
||||
}),
|
||||
props.getKeyProjectLargeScreenDepartmentStatistics({
|
||||
portArea,
|
||||
corpinfoId: currentBranchOffice,
|
||||
}),
|
||||
]);
|
||||
const departmentMap = new Map(
|
||||
keyProjectData.map(item => [
|
||||
item.departmentId,
|
||||
{
|
||||
departmentName: item.departmentName,
|
||||
fourNewHomeworkCount: item.fourNewHomeworkCount,
|
||||
eightWorkCount: 0,
|
||||
morePeopleCount: item.morePeopleCount,
|
||||
},
|
||||
]),
|
||||
);
|
||||
eightWorkData.forEach((item) => {
|
||||
const department = departmentMap.get(item.departmentId) || {
|
||||
departmentName: item.departmentName,
|
||||
fourNewHomeworkCount: 0,
|
||||
eightWorkCount: 0,
|
||||
morePeopleCount: 0,
|
||||
};
|
||||
department.eightWorkCount = item.workCount || 0;
|
||||
departmentMap.set(item.departmentId, department);
|
||||
});
|
||||
setBlock4List([...departmentMap.values()]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getAlarmRecordScreenIotDeviceAlarmPage();
|
||||
getBlock4List();
|
||||
}, []);
|
||||
import AreaAlarmPanel from "./AreaAlarmPanel";
|
||||
import ClosedAreaPersonnelPanel from "./ClosedAreaPersonnelPanel";
|
||||
import GateAndClosedAreaPanel from "./GateAndClosedAreaPanel";
|
||||
import KeyWorkStatsPanel from "./KeyWorkStatsPanel";
|
||||
|
||||
/** 分公司首页右侧区域仅负责按展示顺序组合业务区块。 */
|
||||
function IndexRight() {
|
||||
return (
|
||||
<div className="branch_office_index_right">
|
||||
<div className="block1">
|
||||
<Title title="口门及封闭区域" />
|
||||
<div className="options">
|
||||
<div className="items">
|
||||
{
|
||||
block1List.map((item, index) => (
|
||||
<div className="item" key={index} style={{ backgroundImage: `url(${item.bgImg})` }}>
|
||||
<div className="title">{item.title}</div>
|
||||
<div className="info">
|
||||
<div>
|
||||
{item.label1}
|
||||
:
|
||||
{item.count1}
|
||||
</div>
|
||||
<div>
|
||||
{item.label2}
|
||||
:
|
||||
{item.count2}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="block2">
|
||||
<Title title="封闭区域人员状态" />
|
||||
<div className="options">
|
||||
<div ref={main1Ref} style={{ width: "100%", height: "200px" }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="block3">
|
||||
<Title title="区域告警" />
|
||||
<div className="options">
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">区域名称</div>
|
||||
<div className="td">告警类型</div>
|
||||
<div className="td">告警时间</div>
|
||||
<div className="td">处置状态</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<Spin spinning={props.biStatistics.getAlarmRecordScreenIotDeviceAlarmPageLoading}>
|
||||
<SeamlessScroll list={block3List} step={0.5}>
|
||||
{block3List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.fireRegionName}</div>
|
||||
<div className="td">{item.alarmTypeName}</div>
|
||||
<div className="td">{item.alarmTime}</div>
|
||||
<div className="td">{{ 10: "报警中", 20: "未处置", 30: "已消警" }[item.status]}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</Spin>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="block4">
|
||||
<Title title="重点作业情况统计" />
|
||||
<div className="options">
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">部门名称</div>
|
||||
<div className="td">三人以上作业数</div>
|
||||
<div className="td">危险作业数</div>
|
||||
<div className="td">四新作业数</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<Spin spinning={props.biStatistics.getKeyProjectLargeScreenDepartmentStatisticsLoading || props.biStatistics.getEightWorkInfoScreenDepartmentStatisticsLoading}>
|
||||
<SeamlessScroll list={block4List} step={0.5}>
|
||||
{block4List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.departmentName}</div>
|
||||
<div className="td">{item.morePeopleCount}</div>
|
||||
<div className="td">{item.eightWorkCount}</div>
|
||||
<div className="td">{item.fourNewHomeworkCount}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</Spin>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-index-right">
|
||||
<GateAndClosedAreaPanel />
|
||||
<ClosedAreaPersonnelPanel />
|
||||
<AreaAlarmPanel />
|
||||
<KeyWorkStatsPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_BI_STATISTICS], true)(IndexRight);
|
||||
export default IndexRight;
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
.branch_office_index_right {
|
||||
.block1 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.items {
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
gap: 10px 20px;
|
||||
|
||||
.item {
|
||||
width: calc(50% - 10px);
|
||||
padding: 5px 20px;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block2 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.block3 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.table {
|
||||
margin-top: 5px;
|
||||
|
||||
.scroll {
|
||||
height: 165px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tr {
|
||||
margin-top: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr 2fr 1fr;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block4 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.table {
|
||||
margin-top: 5px;
|
||||
|
||||
.scroll {
|
||||
height: 165px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tr {
|
||||
margin-top: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import CountUp from "react-countup";
|
||||
import closedAreaIcon from "~/assets/images/map_bi/content/ico15.png";
|
||||
import vehiclePassageIcon from "~/assets/images/map_bi/content/ico16.png";
|
||||
import pedestrianPassageIcon from "~/assets/images/map_bi/content/ico17.png";
|
||||
import peopleIcon from "~/assets/images/map_bi/content/ico18.png";
|
||||
import cornerIcon from "~/assets/images/map_bi/content/icon32.png";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ label: "封闭区域数", count: 123, icon: closedAreaIcon },
|
||||
{ label: "车行通道数", count: 123, icon: vehiclePassageIcon },
|
||||
{ label: "人行通道数", count: 123, icon: pedestrianPassageIcon },
|
||||
{ label: "封闭区域当前人数", count: 123, icon: peopleIcon },
|
||||
];
|
||||
|
||||
/** 负责展示封闭区域及通道基础统计。 */
|
||||
function ClosedAreaStatsPanel() {
|
||||
return (
|
||||
<Panel title="封闭区域统计">
|
||||
<div className="branch-office-gate-stats__content">
|
||||
{records.map(item => (
|
||||
<div className="branch-office-gate-stats__item" key={item.label}>
|
||||
<div className="branch-office-gate-stats__image">
|
||||
<img src={item.icon} alt="" />
|
||||
</div>
|
||||
<div className="branch-office-gate-stats__info">
|
||||
<div className="branch-office-gate-stats__label">
|
||||
{item.label}
|
||||
</div>
|
||||
<div className="branch-office-gate-stats__count">
|
||||
<CountUp end={+item.count} />
|
||||
</div>
|
||||
</div>
|
||||
<Corner className="branch-office-gate-stats__corner--top-left" />
|
||||
<Corner className="branch-office-gate-stats__corner--top-right" />
|
||||
<Corner className="branch-office-gate-stats__corner--bottom-left" />
|
||||
<Corner className="branch-office-gate-stats__corner--bottom-right" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
/** 封闭区域统计卡片的四角装饰图标。 */
|
||||
function Corner({ className }) {
|
||||
return (
|
||||
<div className={`branch-office-gate-stats__corner ${className}`}>
|
||||
<img src={cornerIcon} alt="" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ClosedAreaStatsPanel;
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
.branch-office-gate-stats__content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px 20px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: calc(50% - 10px);
|
||||
align-items: center;
|
||||
padding: 9px 0 9px 9px;
|
||||
color: #fff;
|
||||
background-color: rgba(1, 56, 154, 0.26);
|
||||
border: 1px solid #2091f3;
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__image {
|
||||
padding: 8px;
|
||||
margin-right: 10px;
|
||||
background-color: #102561;
|
||||
border: 1px solid #19455b;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__image img {
|
||||
width: 35px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__corner {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__corner--top-left {
|
||||
top: -10px;
|
||||
left: -3px;
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__corner--top-right {
|
||||
top: -3px;
|
||||
right: -10px;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__corner--bottom-left {
|
||||
bottom: -3px;
|
||||
left: -10px;
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.branch-office-gate-stats__corner--bottom-right {
|
||||
right: -3px;
|
||||
bottom: -10px;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
import { useMount } from "ahooks";
|
||||
import * as echarts from "echarts";
|
||||
import { useRef, useState } from "react";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const tabs = ["人员", "车辆"];
|
||||
const records = [
|
||||
{ NAME: "零号门", IN: "0", OUT: "0" },
|
||||
{ NAME: "一号门", IN: "15", OUT: "12" },
|
||||
{ NAME: "二号门", IN: "8", OUT: "10" },
|
||||
{ NAME: "三号门", IN: "22", OUT: "18" },
|
||||
{ NAME: "四号门", IN: "5", OUT: "7" },
|
||||
{ NAME: "五号门", IN: "30", OUT: "25" },
|
||||
{ NAME: "六号门", IN: "12", OUT: "14" },
|
||||
{ NAME: "七号门", IN: "18", OUT: "16" },
|
||||
{ NAME: "八号门", IN: "9", OUT: "11" },
|
||||
{ NAME: "九号门", IN: "25", OUT: "20" },
|
||||
];
|
||||
|
||||
/** 负责展示封闭区域进出趋势并管理图表实例生命周期。 */
|
||||
function EntryExitTrendPanel() {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const chartInstance = useRef(null);
|
||||
const chartRef = useRef(null);
|
||||
|
||||
const initEcharts = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const inData = data.map(item => Number.parseInt(item.IN));
|
||||
const outData = data.map(item => Number.parseInt(item.OUT));
|
||||
const names = data.map(item => item.NAME);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "none",
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ["进", "出"],
|
||||
top: "0%",
|
||||
right: "0%",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 14,
|
||||
},
|
||||
itemWidth: 12,
|
||||
itemHeight: 10,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: "7%",
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 5,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
grid: {
|
||||
left: "10%",
|
||||
right: "5%",
|
||||
top: "10%",
|
||||
bottom: "20%",
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
data: names,
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "进",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(121,103,255,0.7)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#7967FF",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: inData,
|
||||
},
|
||||
{
|
||||
name: "出",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(255,198,124,0.7)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#FFC67C",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: outData,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
||||
useMount(() => {
|
||||
initEcharts(chartRef, chartInstance, records);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title="封闭区域进出情况统计"
|
||||
className="branch-office-gate__trend"
|
||||
extra={(
|
||||
<div className="branch-office-gate-trend__tabs">
|
||||
{tabs.map((item, index) => (
|
||||
<div
|
||||
className={`branch-office-gate-trend__tab ${index === activeIndex ? "branch-office-gate-trend__tab--active" : ""}`}
|
||||
key={item}
|
||||
onClick={() => setActiveIndex(index)}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className="branch-office-gate-trend__content">
|
||||
<div ref={chartRef} className="branch-office-gate-trend__chart" />
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default EntryExitTrendPanel;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
.branch-office-gate__trend {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-gate-trend__tabs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.branch-office-gate-trend__tab {
|
||||
padding: 2px 12px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
background-color: rgba(36, 115, 239, 0.27);
|
||||
border: 1px solid #5d718c;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.branch-office-gate-trend__tab--active {
|
||||
background-color: #2473ef;
|
||||
border-color: #2473ef;
|
||||
}
|
||||
|
||||
.branch-office-gate-trend__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-gate-trend__chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
import { useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const tabs = ["人员", "车辆"];
|
||||
const records = [
|
||||
{
|
||||
permissionRange: "A区",
|
||||
status: "1",
|
||||
applicant: "张三",
|
||||
approver: "李主管",
|
||||
},
|
||||
{
|
||||
permissionRange: "B区",
|
||||
status: "1",
|
||||
applicant: "李四",
|
||||
approver: "王经理",
|
||||
},
|
||||
{
|
||||
permissionRange: "C区",
|
||||
status: "1",
|
||||
applicant: "王五",
|
||||
approver: "赵主任",
|
||||
},
|
||||
{
|
||||
permissionRange: "D区",
|
||||
status: "0",
|
||||
applicant: "赵六",
|
||||
approver: "钱总监",
|
||||
},
|
||||
{
|
||||
permissionRange: "E区",
|
||||
status: "0",
|
||||
applicant: "钱七",
|
||||
approver: "孙部长",
|
||||
},
|
||||
{
|
||||
permissionRange: "F区",
|
||||
status: "0",
|
||||
applicant: "孙八",
|
||||
approver: "周经理",
|
||||
},
|
||||
{
|
||||
permissionRange: "G区",
|
||||
status: "0",
|
||||
applicant: "周九",
|
||||
approver: "吴主任",
|
||||
},
|
||||
{
|
||||
permissionRange: "H区",
|
||||
status: "1",
|
||||
applicant: "吴十",
|
||||
approver: "郑主管",
|
||||
},
|
||||
{
|
||||
permissionRange: "I区",
|
||||
status: "0",
|
||||
applicant: "郑一",
|
||||
approver: "王总监",
|
||||
},
|
||||
{
|
||||
permissionRange: "J区",
|
||||
status: "1",
|
||||
applicant: "王二",
|
||||
approver: "张部长",
|
||||
},
|
||||
];
|
||||
|
||||
/** 负责展示口门申请记录及人员、车辆分类标签状态。 */
|
||||
function GateApplicationPanel() {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title="口门申请记录"
|
||||
className="branch-office-gate__application"
|
||||
extra={(
|
||||
<div className="branch-office-gate-application__tabs">
|
||||
{tabs.map((item, index) => (
|
||||
<div
|
||||
className={`branch-office-gate-application__tab ${index === activeIndex ? "branch-office-gate-application__tab--active" : ""}`}
|
||||
key={item}
|
||||
onClick={() => setActiveIndex(index)}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className="branch-office-gate-application__content">
|
||||
<div className="branch-office-gate-application__table">
|
||||
<div className="branch-office-gate-application__row">
|
||||
<div>权限范围</div>
|
||||
<div>申请类型</div>
|
||||
<div>申请人</div>
|
||||
<div>审批人</div>
|
||||
</div>
|
||||
<div className="branch-office-gate-application__body">
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div
|
||||
className="branch-office-gate-application__row"
|
||||
key={index}
|
||||
>
|
||||
<div>{item.permissionRange}</div>
|
||||
<div
|
||||
className={`branch-office-gate-application__type branch-office-gate-application__type--${item.status}`}
|
||||
>
|
||||
{item.status === "1" ? "临时" : "长期"}
|
||||
</div>
|
||||
<div>{item.applicant}</div>
|
||||
<div>{item.approver}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default GateApplicationPanel;
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
.branch-office-gate__application {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-gate-application__tabs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.branch-office-gate-application__tab {
|
||||
padding: 2px 12px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
background-color: rgba(36, 115, 239, 0.27);
|
||||
border: 1px solid #5d718c;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.branch-office-gate-application__tab--active {
|
||||
background-color: #2473ef;
|
||||
border-color: #2473ef;
|
||||
}
|
||||
|
||||
.branch-office-gate-application__content {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.branch-office-gate-application__body {
|
||||
height: 300px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-gate-application__row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
background-color: rgba(42, 86, 158, 0.53);
|
||||
}
|
||||
|
||||
.branch-office-gate-application__body
|
||||
.branch-office-gate-application__row:nth-child(odd) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.branch-office-gate-application__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.branch-office-gate-application__row .branch-office-gate-application__type--1 {
|
||||
color: #fc6b13;
|
||||
}
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
import * as echarts from "echarts";
|
||||
|
||||
export const initEcharts1 = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const inData = data.map(item => Number.parseInt(item.IN));
|
||||
const outData = data.map(item => Number.parseInt(item.OUT));
|
||||
const names = data.map(item => item.NAME);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "none",
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ["进", "出"],
|
||||
top: "0%",
|
||||
right: "0%",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 14,
|
||||
},
|
||||
itemWidth: 12,
|
||||
itemHeight: 10,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: "7%",
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 5,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
grid: {
|
||||
left: "10%",
|
||||
right: "5%",
|
||||
top: "10%",
|
||||
bottom: "20%",
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
data: names,
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "进",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(121,103,255,0.7)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#7967FF",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: inData,
|
||||
},
|
||||
{
|
||||
name: "出",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(255,198,124,0.7)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#FFC67C",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: outData,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
|
@ -1,172 +1,14 @@
|
|||
import { useMount } from "ahooks";
|
||||
import { useRef, useState } from "react";
|
||||
import CountUp from "react-countup";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import icon1 from "~/assets/images/map_bi/content/ico15.png";
|
||||
import icon2 from "~/assets/images/map_bi/content/ico16.png";
|
||||
import icon3 from "~/assets/images/map_bi/content/ico17.png";
|
||||
import icon4 from "~/assets/images/map_bi/content/ico18.png";
|
||||
import icon5 from "~/assets/images/map_bi/content/icon32.png";
|
||||
import Title from "~/pages/Container/Map/components/Content/branchOffice/Title";
|
||||
import { initEcharts1 } from "./echarts";
|
||||
import "./index.less";
|
||||
import ClosedAreaStatsPanel from "./ClosedAreaStatsPanel";
|
||||
import EntryExitTrendPanel from "./EntryExitTrendPanel";
|
||||
import GateApplicationPanel from "./GateApplicationPanel";
|
||||
|
||||
const block2OptionsNavList = ["人员", "车辆"];
|
||||
const block3OptionsNavList = ["人员", "车辆"];
|
||||
/** 分公司门禁模块仅负责按展示顺序组合业务区块。 */
|
||||
function MenJin() {
|
||||
const [block1List, setBlock1List] = useState([
|
||||
{ label: "封闭区域数", count: 123, icon: icon1 },
|
||||
{ label: "车行通道数", count: 123, icon: icon2 },
|
||||
{ label: "人行通道数", count: 123, icon: icon3 },
|
||||
{ label: "封闭区域当前人数", count: 123, icon: icon4 },
|
||||
]);
|
||||
const [block2Index, setBlock2Index] = useState(0);
|
||||
const [block3Index, setBlock3Index] = useState(0);
|
||||
const [block3List, setBlock3List] = useState([
|
||||
{ permissionRange: "A区", status: "1", applicant: "张三", approver: "李主管" },
|
||||
{ permissionRange: "B区", status: "1", applicant: "李四", approver: "王经理" },
|
||||
{ permissionRange: "C区", status: "1", applicant: "王五", approver: "赵主任" },
|
||||
{ permissionRange: "D区", status: "0", applicant: "赵六", approver: "钱总监" },
|
||||
{ permissionRange: "E区", status: "0", applicant: "钱七", approver: "孙部长" },
|
||||
{ permissionRange: "F区", status: "0", applicant: "孙八", approver: "周经理" },
|
||||
{ permissionRange: "G区", status: "0", applicant: "周九", approver: "吴主任" },
|
||||
{ permissionRange: "H区", status: "1", applicant: "吴十", approver: "郑主管" },
|
||||
{ permissionRange: "I区", status: "0", applicant: "郑一", approver: "王总监" },
|
||||
{ permissionRange: "J区", status: "1", applicant: "王二", approver: "张部长" },
|
||||
]);
|
||||
|
||||
const chartInstance = useRef(null);
|
||||
const main1Ref = useRef(null);
|
||||
|
||||
useMount(() => {
|
||||
initEcharts1(main1Ref, chartInstance, [
|
||||
{ NAME: "零号门", IN: "0", OUT: "0" },
|
||||
{ NAME: "一号门", IN: "15", OUT: "12" },
|
||||
{ NAME: "二号门", IN: "8", OUT: "10" },
|
||||
{ NAME: "三号门", IN: "22", OUT: "18" },
|
||||
{ NAME: "四号门", IN: "5", OUT: "7" },
|
||||
{ NAME: "五号门", IN: "30", OUT: "25" },
|
||||
{ NAME: "六号门", IN: "12", OUT: "14" },
|
||||
{ NAME: "七号门", IN: "18", OUT: "16" },
|
||||
{ NAME: "八号门", IN: "9", OUT: "11" },
|
||||
{ NAME: "九号门", IN: "25", OUT: "20" },
|
||||
]);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const block2OptionsClick = (index) => {
|
||||
if (index === block2Index)
|
||||
return;
|
||||
setBlock2Index(index);
|
||||
};
|
||||
|
||||
const block3OptionsClick = (index) => {
|
||||
if (index === block3Index)
|
||||
return;
|
||||
setBlock3Index(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="branch_office_menjin">
|
||||
<div className="block1">
|
||||
<Title title="封闭区域统计" />
|
||||
<div className="options">
|
||||
<div className="items">
|
||||
{
|
||||
block1List.map((item, index) => (
|
||||
<div className="item" key={index}>
|
||||
<div className="img">
|
||||
<img src={item.icon} alt="" />
|
||||
</div>
|
||||
<div className="info">
|
||||
<div className="label">{item.label}</div>
|
||||
<div className="count">
|
||||
<CountUp end={+item.count}></CountUp>
|
||||
</div>
|
||||
</div>
|
||||
<div className="corner-img top-left-img">
|
||||
<img src={icon5} alt="" />
|
||||
</div>
|
||||
<div className="corner-img top-right-img">
|
||||
<img src={icon5} alt="" />
|
||||
</div>
|
||||
<div className="corner-img bottom-left-img">
|
||||
<img src={icon5} alt="" />
|
||||
</div>
|
||||
<div className="corner-img bottom-right-img">
|
||||
<img src={icon5} alt="" />
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="block2">
|
||||
<Title
|
||||
title="封闭区域进出情况统计"
|
||||
extra={(
|
||||
<div className="tabs">
|
||||
{block2OptionsNavList.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`tab ${index === block2Index ? "active" : ""}`}
|
||||
onClick={() => block2OptionsClick(index)}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<div className="options">
|
||||
<div ref={main1Ref} style={{ width: "100%", height: "300px" }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="block3">
|
||||
<Title
|
||||
title="口门申请记录"
|
||||
extra={(
|
||||
<div className="tabs">
|
||||
{block3OptionsNavList.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`tab ${index === block3Index ? "active" : ""}`}
|
||||
onClick={() => block3OptionsClick(index)}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">权限范围</div>
|
||||
<div className="td">申请类型</div>
|
||||
<div className="td">申请人</div>
|
||||
<div className="td">审批人</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={block3List} step={0.5}>
|
||||
{block3List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.permissionRange}</div>
|
||||
<div className="td" style={{ color: item.status === "1" ? "#FC6B13" : "#fff" }}>{item.status === "1" ? "临时" : "长期"}</div>
|
||||
<div className="td">{item.applicant}</div>
|
||||
<div className="td">{item.approver}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-gate">
|
||||
<ClosedAreaStatsPanel />
|
||||
<EntryExitTrendPanel />
|
||||
<GateApplicationPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,168 +0,0 @@
|
|||
.branch_office_menjin {
|
||||
.tabs-style() {
|
||||
display: flex;
|
||||
|
||||
.tab {
|
||||
background-color: rgba(36, 115, 239, 0.27);
|
||||
padding: 2px 12px;
|
||||
border-radius: 2px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
border: 1px solid #5d718c;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
background-color: #2473ef;
|
||||
border: 1px solid #2473ef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block1 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.items {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
gap: 10px 20px;
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
width: calc(50% - 10px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
padding: 9px 0 9px 9px;
|
||||
background-color: rgba(1, 56, 154, 0.26);
|
||||
border: 1px solid #2091F3;
|
||||
|
||||
.img {
|
||||
background-color: #102561;
|
||||
border: 1px solid #19455B;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 35px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
.label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.count {
|
||||
}
|
||||
}
|
||||
|
||||
.corner-img {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
|
||||
&.top-left-img {
|
||||
top: -10px;
|
||||
left: -3px;
|
||||
}
|
||||
|
||||
&.top-right-img {
|
||||
transform: rotate(90deg);
|
||||
top: -3px;
|
||||
right: -10px;
|
||||
}
|
||||
|
||||
&.bottom-left-img {
|
||||
transform: rotate(270deg);
|
||||
bottom: -3px;
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
&.bottom-right-img {
|
||||
transform: rotate(180deg);
|
||||
bottom: -10px;
|
||||
right: -3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block2 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.tabs {
|
||||
.tabs-style();
|
||||
}
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.block3 {
|
||||
background-image: linear-gradient(to bottom,
|
||||
rgba(0, 0, 0, 0),
|
||||
rgba(0, 0, 0, 0.8));
|
||||
margin-top: 10px;
|
||||
|
||||
.tabs {
|
||||
.tabs-style();
|
||||
}
|
||||
|
||||
.table {
|
||||
padding: 10px;
|
||||
|
||||
.scroll {
|
||||
height: 300px;
|
||||
overflow-y: hidden;
|
||||
|
||||
.tr {
|
||||
&:nth-child(odd) {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tr {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
background-color: rgba(42, 86, 158, 0.53);
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
|
||||
&.green {
|
||||
color: #7ccf41;
|
||||
}
|
||||
|
||||
&.yellow {
|
||||
color: #ffcb05;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ source: "国家气象局", level: "蓝色", area: "北京市朝阳区" },
|
||||
{ source: "地方气象台", level: "黄色", area: "上海市浦东新区" },
|
||||
{ source: "中央气象台", level: "橙色", area: "广州市天河区" },
|
||||
{ source: "区域气象中心", level: "红色", area: "深圳市南山区" },
|
||||
{ source: "国家气象局", level: "蓝色", area: "杭州市西湖区" },
|
||||
{ source: "地方气象台", level: "黄色", area: "成都市锦江区" },
|
||||
{ source: "中央气象台", level: "橙色", area: "武汉市江汉区" },
|
||||
{ source: "区域气象中心", level: "红色", area: "西安市雁塔区" },
|
||||
{ source: "国家气象局", level: "蓝色", area: "南京市鼓楼区" },
|
||||
{ source: "地方气象台", level: "黄色", area: "重庆市渝中区" },
|
||||
];
|
||||
|
||||
/** 负责展示本地气象告警信息表格。 */
|
||||
function WeatherAlarmPanel() {
|
||||
return (
|
||||
<Panel title="气象告警信息" className="branch-office-weather__alarm">
|
||||
<div className="branch-office-weather-alarm__content">
|
||||
<div className="branch-office-weather-alarm__table">
|
||||
<div className="branch-office-weather-alarm__row">
|
||||
<div>预警信息来源</div>
|
||||
<div>预警级别</div>
|
||||
<div>影响区域</div>
|
||||
</div>
|
||||
<div className="branch-office-weather-alarm__body">
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div className="branch-office-weather-alarm__row" key={index}>
|
||||
<div>{item.source}</div>
|
||||
<div>{item.level}</div>
|
||||
<div>{item.area}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default WeatherAlarmPanel;
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
.branch-office-weather__alarm {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-weather-alarm__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-weather-alarm__table {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-office-weather-alarm__body {
|
||||
height: 300px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-weather-alarm__row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
margin-top: 5px;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
}
|
||||
|
||||
.branch-office-weather-alarm__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { Spin } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import precipitationIcon from "~/assets/images/public/bigScreen/ico21.png";
|
||||
import temperatureIcon from "~/assets/images/public/bigScreen/img10.png";
|
||||
import windIcon from "~/assets/images/public/bigScreen/img11.png";
|
||||
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import { getAlertColor, getWeatherIcon } from "~/utils/weather";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ department: "技术部", requiredDevices: 150, anchoredDevices: 142 },
|
||||
{ department: "销售部", requiredDevices: 80, anchoredDevices: 76 },
|
||||
{ department: "市场部", requiredDevices: 60, anchoredDevices: 58 },
|
||||
{ department: "运营部", requiredDevices: 120, anchoredDevices: 115 },
|
||||
{ department: "客服部", requiredDevices: 90, anchoredDevices: 88 },
|
||||
{ department: "财务部", requiredDevices: 30, anchoredDevices: 29 },
|
||||
{ department: "人事部", requiredDevices: 25, anchoredDevices: 24 },
|
||||
{ department: "研发部", requiredDevices: 200, anchoredDevices: 195 },
|
||||
{ department: "质量部", requiredDevices: 45, anchoredDevices: 42 },
|
||||
{ department: "采购部", requiredDevices: 35, anchoredDevices: 33 },
|
||||
];
|
||||
|
||||
/** 负责查询并展示天气、预警和部门设备锚定情况。 */
|
||||
function WeatherPreventionPanel(props) {
|
||||
const [weather, setWeather] = useState({});
|
||||
const [alerts, setAlerts] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadWeather = async () => {
|
||||
const { result = {} } = await props.getWeather();
|
||||
setWeather(result.now || {});
|
||||
setAlerts(Array.isArray(result.alerts) ? result.alerts : []);
|
||||
};
|
||||
loadWeather();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Panel title="天气预防情况">
|
||||
<Spin spinning={props.biStatistics.getWeatherLoading}>
|
||||
<div className="branch-office-weather-data__content">
|
||||
<div className="branch-office-weather-data__weather">
|
||||
<div className="branch-office-weather-data__condition">
|
||||
<img src={getWeatherIcon(weather.text)} alt="" />
|
||||
<div>{weather.text || "暂无"}</div>
|
||||
</div>
|
||||
<div className="branch-office-weather-data__metrics">
|
||||
<WeatherMetric
|
||||
icon={temperatureIcon}
|
||||
label="温度:"
|
||||
value={weather.temp ? `${weather.temp}℃` : "--"}
|
||||
/>
|
||||
<WeatherMetric
|
||||
icon={windIcon}
|
||||
label="风速:"
|
||||
value={weather.wind_class || "--"}
|
||||
/>
|
||||
<WeatherMetric
|
||||
icon={precipitationIcon}
|
||||
label="降水量:"
|
||||
value={weather.prec_1h ? `${weather.prec_1h}毫米` : "--"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-weather-data__alerts">
|
||||
<SeamlessScroll
|
||||
list={alerts}
|
||||
step={0.5}
|
||||
limitScrollNum={2}
|
||||
singleHeight={22}
|
||||
>
|
||||
{alerts.map((item, index) => (
|
||||
<div
|
||||
className="branch-office-weather-data__alert"
|
||||
key={index}
|
||||
style={{ color: getAlertColor(item.level) }}
|
||||
>
|
||||
{item.title}
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
<div className="branch-office-weather-data__table">
|
||||
<div className="branch-office-weather-data__row">
|
||||
<div>部门名称</div>
|
||||
<div>需锚定设备数</div>
|
||||
<div>已锚定设备数</div>
|
||||
</div>
|
||||
<div className="branch-office-weather-data__table-body">
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div className="branch-office-weather-data__row" key={index}>
|
||||
<div>{item.department}</div>
|
||||
<div>{item.requiredDevices}</div>
|
||||
<div>{item.anchoredDevices}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
/** 天气区块中的单项实时气象指标。 */
|
||||
function WeatherMetric({ icon, label, value }) {
|
||||
return (
|
||||
<div className="branch-office-weather-data__metric">
|
||||
<img src={icon} alt="" />
|
||||
<div>
|
||||
<div className="branch-office-weather-data__metric-label">{label}</div>
|
||||
<div className="branch-office-weather-data__metric-value">{value}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_BI_STATISTICS], true)(WeatherPreventionPanel);
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
.branch-office-weather-data__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__weather {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__condition {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__condition img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__condition div {
|
||||
letter-spacing: 5px;
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__metrics {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 10px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__metric {
|
||||
display: flex;
|
||||
width: calc((100% / 2) - 10px);
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__metric img {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__metric-label {
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__metric-value {
|
||||
color: #00e7ff;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__alerts {
|
||||
height: 20px;
|
||||
margin-top: 10px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__alert {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__table {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__table-body {
|
||||
height: 200px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
margin-top: 5px;
|
||||
background-image: linear-gradient(to bottom,
|
||||
rgba(0, 42, 85, 0.38),
|
||||
rgba(1, 37, 74, 0.47),
|
||||
rgba(4, 38, 87, 0));
|
||||
border: 1px solid;
|
||||
border-bottom: none;
|
||||
border-image: linear-gradient(to top,
|
||||
rgba(8, 41, 87, 0.5),
|
||||
rgba(64, 152, 255, 0.5)) 1;
|
||||
}
|
||||
|
||||
.branch-office-weather-data__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -1,152 +1,14 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { useEffect, useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import icon3 from "~/assets/images/public/bigScreen/ico21.png";
|
||||
import icon1 from "~/assets/images/public/bigScreen/img10.png";
|
||||
import icon2 from "~/assets/images/public/bigScreen/img11.png";
|
||||
import { NS_BI_STATISTICS } from "~/enumerate/namespace";
|
||||
import Title from "~/pages/Container/Map/components/Content/branchOffice/Title";
|
||||
import { getAlertColor, getWeatherIcon } from "~/utils/weather";
|
||||
import "./index.less";
|
||||
|
||||
function QiXiang(props) {
|
||||
const [weatherData, setWeatherData] = useState({});
|
||||
const [alert, setAlert] = useState([]);
|
||||
const [block1List, setBlock1List] = useState([
|
||||
{ department: "技术部", requiredDevices: 150, anchoredDevices: 142 },
|
||||
{ department: "销售部", requiredDevices: 80, anchoredDevices: 76 },
|
||||
{ department: "市场部", requiredDevices: 60, anchoredDevices: 58 },
|
||||
{ department: "运营部", requiredDevices: 120, anchoredDevices: 115 },
|
||||
{ department: "客服部", requiredDevices: 90, anchoredDevices: 88 },
|
||||
{ department: "财务部", requiredDevices: 30, anchoredDevices: 29 },
|
||||
{ department: "人事部", requiredDevices: 25, anchoredDevices: 24 },
|
||||
{ department: "研发部", requiredDevices: 200, anchoredDevices: 195 },
|
||||
{ department: "质量部", requiredDevices: 45, anchoredDevices: 42 },
|
||||
{ department: "采购部", requiredDevices: 35, anchoredDevices: 33 },
|
||||
]);
|
||||
const [block2List, setBlock2List] = useState([
|
||||
{ source: "国家气象局", level: "蓝色", area: "北京市朝阳区" },
|
||||
{ source: "地方气象台", level: "黄色", area: "上海市浦东新区" },
|
||||
{ source: "中央气象台", level: "橙色", area: "广州市天河区" },
|
||||
{ source: "区域气象中心", level: "红色", area: "深圳市南山区" },
|
||||
{ source: "国家气象局", level: "蓝色", area: "杭州市西湖区" },
|
||||
{ source: "地方气象台", level: "黄色", area: "成都市锦江区" },
|
||||
{ source: "中央气象台", level: "橙色", area: "武汉市江汉区" },
|
||||
{ source: "区域气象中心", level: "红色", area: "西安市雁塔区" },
|
||||
{ source: "国家气象局", level: "蓝色", area: "南京市鼓楼区" },
|
||||
{ source: "地方气象台", level: "黄色", area: "重庆市渝中区" },
|
||||
]);
|
||||
|
||||
const getWeatherData = async () => {
|
||||
const { result = {} } = await props.getWeather();
|
||||
setWeatherData(result.now);
|
||||
setAlert(Array.isArray(result.alerts) ? result.alerts : []);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getWeatherData();
|
||||
}, []);
|
||||
import WeatherAlarmPanel from "./WeatherAlarmPanel";
|
||||
import WeatherPreventionPanel from "./WeatherPreventionPanel";
|
||||
|
||||
/** 分公司气象模块仅负责按展示顺序组合业务区块。 */
|
||||
function QiXiang() {
|
||||
return (
|
||||
<div className="branch_office_qixiang">
|
||||
<div className="block1">
|
||||
<Title title="天气预防情况" />
|
||||
<div className="options">
|
||||
<div className="weather">
|
||||
<div className="icon">
|
||||
<div className="img">
|
||||
<img src={getWeatherIcon(weatherData.text)} alt="" />
|
||||
</div>
|
||||
<div className="text">{weatherData.text || "暂无"}</div>
|
||||
</div>
|
||||
<div className="items">
|
||||
<div className="item">
|
||||
<div className="img">
|
||||
<img src={icon1} alt="" />
|
||||
</div>
|
||||
<div className="info">
|
||||
<div className="label">温度:</div>
|
||||
<div className="value">{weatherData.temp ? `${weatherData.temp}℃` : "--"}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="item">
|
||||
<div className="img">
|
||||
<img src={icon2} alt="" />
|
||||
</div>
|
||||
<div className="info">
|
||||
<div className="label">风速:</div>
|
||||
<div className="value">{weatherData.wind_class || "--"}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="item">
|
||||
<div className="img">
|
||||
<img src={icon3} alt="" />
|
||||
</div>
|
||||
<div className="info">
|
||||
<div className="label">降水量:</div>
|
||||
<div className="value">{weatherData.prec_1h ? `${weatherData.prec_1h}毫米` : "--"}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="alert">
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={alert} step={0.5} limitScrollNum={2} singleHeight={22}>
|
||||
{
|
||||
alert.map((item, index) => (
|
||||
<div className="item" key={index}>
|
||||
<div className="title" style={{ color: getAlertColor(item.level) }}>{item.title}</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">部门名称</div>
|
||||
<div className="td">需锚定设备数</div>
|
||||
<div className="td">已锚定设备数</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={block1List} step={0.5}>
|
||||
{block1List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.department}</div>
|
||||
<div className="td">{item.requiredDevices}</div>
|
||||
<div className="td">{item.anchoredDevices}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="block2">
|
||||
<Title title="气象告警信息" />
|
||||
<div className="options">
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">预警信息来源</div>
|
||||
<div className="td">预警级别</div>
|
||||
<div className="td">影响区域</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={block2List} step={0.5}>
|
||||
{block2List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.source}</div>
|
||||
<div className="td">{item.level}</div>
|
||||
<div className="td">{item.area}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-weather">
|
||||
<WeatherPreventionPanel />
|
||||
<WeatherAlarmPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_BI_STATISTICS], true)(QiXiang);
|
||||
export default QiXiang;
|
||||
|
|
|
|||
|
|
@ -1,153 +0,0 @@
|
|||
.branch_office_qixiang{
|
||||
.block1 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.weather {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
|
||||
.icon {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
|
||||
.img {
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
color: #fff;
|
||||
writing-mode: vertical-lr;
|
||||
letter-spacing: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 10px;
|
||||
|
||||
.item {
|
||||
width: calc((100% / 2) - 10px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.img {
|
||||
img {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
.label {
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 18px;
|
||||
color: #00e7ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alert {
|
||||
margin-top: 10px;
|
||||
|
||||
.scroll {
|
||||
height: 20px;
|
||||
overflow-y: hidden;
|
||||
|
||||
.item {
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
margin-top: 5px;
|
||||
|
||||
.scroll {
|
||||
height: 200px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tr {
|
||||
margin-top: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
background-image: linear-gradient(to bottom, rgba(0, 42, 85, 0.38), rgba(1, 37, 74, 0.47), rgba(4, 38, 87, 0));
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to top, rgba(8, 41, 87, 0.5), rgba(64, 152, 255, 0.5)) 1;
|
||||
border-bottom: none;
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block2 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.table {
|
||||
margin-top: 5px;
|
||||
|
||||
.scroll {
|
||||
height: 300px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tr {
|
||||
margin-top: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ alarmContent: "SOS紧急告警", personnelInvolved: "张三", dispositionStatus: 1 },
|
||||
{ alarmContent: "静止/滞留告警", personnelInvolved: "李四", dispositionStatus: 2 },
|
||||
{ alarmContent: "电子围栏越界", personnelInvolved: "王五", dispositionStatus: 1 },
|
||||
{ alarmContent: "非授权区域停留", personnelInvolved: "赵六", dispositionStatus: 3 },
|
||||
{ alarmContent: "设备及信号类告警", personnelInvolved: "钱七", dispositionStatus: 1 },
|
||||
{ alarmContent: "聚集告警", personnelInvolved: "孙八", dispositionStatus: 2 },
|
||||
{ alarmContent: "单独作业告警", personnelInvolved: "周九", dispositionStatus: 1 },
|
||||
{ alarmContent: "超员/缺员告警", personnelInvolved: "吴十", dispositionStatus: 3 },
|
||||
{ alarmContent: "SOS紧急告警", personnelInvolved: "郑一", dispositionStatus: 1 },
|
||||
{ alarmContent: "静止/滞留告警", personnelInvolved: "王二", dispositionStatus: 2 },
|
||||
];
|
||||
|
||||
const dispositionText = { 1: "已处置", 2: "未处置", 3: "处置中" };
|
||||
|
||||
/** 负责展示人员告警处置状态列表。 */
|
||||
function AlarmHandlingPanel() {
|
||||
return (
|
||||
<Panel title="告警处置情况" className="branch-office-personnel__alarm-handling">
|
||||
<div className="branch-office-alarm-handling__content">
|
||||
<div className="branch-office-alarm-handling__table">
|
||||
<div className="branch-office-alarm-handling__row">
|
||||
<div>报警内容</div>
|
||||
<div>涉及人员</div>
|
||||
<div>处置情况</div>
|
||||
</div>
|
||||
<div className="branch-office-alarm-handling__body">
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div className="branch-office-alarm-handling__row" key={index}>
|
||||
<div>{item.alarmContent}</div>
|
||||
<div>{item.personnelInvolved}</div>
|
||||
<div
|
||||
className={`branch-office-alarm-handling__status branch-office-alarm-handling__status--${item.dispositionStatus}`}
|
||||
>
|
||||
{dispositionText[item.dispositionStatus]}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default AlarmHandlingPanel;
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
.branch-office-personnel__alarm-handling {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-alarm-handling__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-alarm-handling__table {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-office-alarm-handling__body {
|
||||
height: 100px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-alarm-handling__row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
margin-top: 5px;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
}
|
||||
|
||||
.branch-office-alarm-handling__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.branch-office-alarm-handling__row .branch-office-alarm-handling__status--1 {
|
||||
color: #1db924;
|
||||
}
|
||||
|
||||
.branch-office-alarm-handling__row .branch-office-alarm-handling__status--2 {
|
||||
color: #ff611c;
|
||||
}
|
||||
|
||||
.branch-office-alarm-handling__row .branch-office-alarm-handling__status--3 {
|
||||
color: #258ff1;
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import { useMount } from "ahooks";
|
||||
import * as echarts from "echarts";
|
||||
import { useRef } from "react";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ name: "SOS紧急告警", value: "120" },
|
||||
{ name: "静止/滞留告警", value: "10" },
|
||||
{ name: "电子围栏越界", value: "10" },
|
||||
{ name: "非授权区域停留", value: "20" },
|
||||
{ name: "设备及信号类告警", value: "30" },
|
||||
{ name: "聚集告警", value: "40" },
|
||||
{ name: "单独作业告警", value: "50" },
|
||||
{ name: "超员/缺员告警", value: "60" },
|
||||
{ name: "已处置报警数/报警数", value: "10" },
|
||||
];
|
||||
|
||||
/** 负责展示报警类型占比图,并管理图表实例生命周期。 */
|
||||
function AlarmTypeChartPanel() {
|
||||
const chartInstance = useRef(null);
|
||||
const chartRef = useRef(null);
|
||||
|
||||
const initEcharts = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
},
|
||||
legend: {
|
||||
left: "center",
|
||||
top: "0",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
color: ["#4198AF", "#285DF0", "#EA439D", "#F59FBC", "#FCA158", "#03D4B9", "#9FD224", "#13C871", "#FF611C"],
|
||||
type: "pie",
|
||||
radius: [0, "50%"],
|
||||
center: ["50%", "60%"],
|
||||
label: {
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
data,
|
||||
}],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
||||
useMount(() => {
|
||||
initEcharts(chartRef, chartInstance, records);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Panel title="报警类型">
|
||||
<div className="branch-office-alarm-type-chart__content">
|
||||
<div ref={chartRef} className="branch-office-alarm-type-chart__chart" />
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default AlarmTypeChartPanel;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
.branch-office-alarm-type-chart__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-alarm-type-chart__chart {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
import { useMount } from "ahooks";
|
||||
import * as echarts from "echarts";
|
||||
import { useRef } from "react";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ name: "A区", unitPersonnelCount: 120, relatedPartyPersonnelCount: 85 },
|
||||
{ name: "B区", unitPersonnelCount: 95, relatedPartyPersonnelCount: 70 },
|
||||
{ name: "C区", unitPersonnelCount: 80, relatedPartyPersonnelCount: 60 },
|
||||
{ name: "D区", unitPersonnelCount: 150, relatedPartyPersonnelCount: 110 },
|
||||
{ name: "E区", unitPersonnelCount: 75, relatedPartyPersonnelCount: 55 },
|
||||
{ name: "F区", unitPersonnelCount: 110, relatedPartyPersonnelCount: 80 },
|
||||
{ name: "G区", unitPersonnelCount: 65, relatedPartyPersonnelCount: 45 },
|
||||
{ name: "H区", unitPersonnelCount: 140, relatedPartyPersonnelCount: 100 },
|
||||
{ name: "I区", unitPersonnelCount: 90, relatedPartyPersonnelCount: 65 },
|
||||
{ name: "J区", unitPersonnelCount: 125, relatedPartyPersonnelCount: 90 },
|
||||
];
|
||||
|
||||
/** 负责展示封闭区域人员统计图,并管理图表实例生命周期。 */
|
||||
function ClosedAreaPersonnelPanel() {
|
||||
const chartInstance = useRef(null);
|
||||
const chartRef = useRef(null);
|
||||
|
||||
const initEcharts = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const unitPersonnelData = data.map(item => Number.parseInt(item.unitPersonnelCount));
|
||||
const relatedPartyPersonnelData = data.map(item => Number.parseInt(item.relatedPartyPersonnelCount));
|
||||
const names = data.map(item => item.name);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "none",
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ["单位人员数", "相关方人员数"],
|
||||
top: "0%",
|
||||
right: "0%",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 14,
|
||||
},
|
||||
itemWidth: 12,
|
||||
itemHeight: 10,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: "7%",
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 5,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
grid: {
|
||||
left: "10%",
|
||||
right: "5%",
|
||||
top: "15%",
|
||||
bottom: "25%",
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
data: names,
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "单位人员数",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(84,173,147,0.2)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#54AD93",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: unitPersonnelData,
|
||||
},
|
||||
{
|
||||
name: "相关方人员数",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(72,117,231,0.2)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#4875E7",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: relatedPartyPersonnelData,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
||||
useMount(() => {
|
||||
initEcharts(chartRef, chartInstance, records);
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title="封闭区域人员统计情况"
|
||||
className="branch-office-personnel__area-statistics"
|
||||
>
|
||||
<div className="branch-office-area-personnel__content">
|
||||
<div ref={chartRef} className="branch-office-area-personnel__chart" />
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default ClosedAreaPersonnelPanel;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.branch-office-personnel__area-statistics {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-area-personnel__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-area-personnel__chart {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import Panel from "~/pages/Container/Map/components/Content/branchOffice/Panel";
|
||||
import "./index.less";
|
||||
|
||||
const records = [
|
||||
{ name: "张三", area: "A区", onlineStatus: 1 },
|
||||
{ name: "李四", area: "B区", onlineStatus: 1 },
|
||||
{ name: "王五", area: "C区", onlineStatus: 2 },
|
||||
{ name: "赵六", area: "D区", onlineStatus: 1 },
|
||||
{ name: "钱七", area: "E区", onlineStatus: 1 },
|
||||
{ name: "孙八", area: "F区", onlineStatus: 2 },
|
||||
{ name: "周九", area: "G区", onlineStatus: 1 },
|
||||
{ name: "吴十", area: "H区", onlineStatus: 1 },
|
||||
{ name: "郑一", area: "I区", onlineStatus: 2 },
|
||||
{ name: "王二", area: "J区", onlineStatus: 1 },
|
||||
];
|
||||
|
||||
/** 负责展示人员定位与在线状态列表。 */
|
||||
function PersonnelLocationPanel() {
|
||||
return (
|
||||
<Panel title="人员定位列表" className="branch-office-personnel__location">
|
||||
<div className="branch-office-personnel-location__content">
|
||||
<div className="branch-office-personnel-location__table">
|
||||
<div className="branch-office-personnel-location__row">
|
||||
<div>人员姓名</div>
|
||||
<div>所属区域</div>
|
||||
<div>在线状态</div>
|
||||
</div>
|
||||
<div className="branch-office-personnel-location__body">
|
||||
<SeamlessScroll list={records} step={0.5}>
|
||||
{records.map((item, index) => (
|
||||
<div className="branch-office-personnel-location__row" key={index}>
|
||||
<div>{item.name}</div>
|
||||
<div>{item.area}</div>
|
||||
<div
|
||||
className={`branch-office-personnel-location__status branch-office-personnel-location__status--${item.onlineStatus}`}
|
||||
>
|
||||
{item.onlineStatus === 1 ? "在线" : "离线"}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export default PersonnelLocationPanel;
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
.branch-office-personnel__location {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-office-personnel-location__content {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.branch-office-personnel-location__table {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-office-personnel-location__body {
|
||||
height: 100px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.branch-office-personnel-location__row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
margin-top: 5px;
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
}
|
||||
|
||||
.branch-office-personnel-location__row div {
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.branch-office-personnel-location__row .branch-office-personnel-location__status--1 {
|
||||
color: #1db924;
|
||||
}
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
import * as echarts from "echarts";
|
||||
|
||||
export const initEcharts1 = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
},
|
||||
legend: {
|
||||
left: "center",
|
||||
top: "0",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
color: ["#4198AF", "#285DF0", "#EA439D", "#F59FBC", "#FCA158", "#03D4B9", "#9FD224", "#13C871", "#FF611C"],
|
||||
type: "pie",
|
||||
radius: [0, "50%"],
|
||||
center: ["50%", "60%"],
|
||||
label: {
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
data,
|
||||
}],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
||||
export const initEcharts2 = (mainRef, chartInstance, data) => {
|
||||
chartInstance.current = echarts.init(mainRef.current);
|
||||
|
||||
const unitPersonnelData = data.map(item => Number.parseInt(item.unitPersonnelCount));
|
||||
const relatedPartyPersonnelData = data.map(item => Number.parseInt(item.relatedPartyPersonnelCount));
|
||||
const names = data.map(item => item.name);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "none",
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ["单位人员数", "相关方人员数"],
|
||||
top: "0%",
|
||||
right: "0%",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 14,
|
||||
},
|
||||
itemWidth: 12,
|
||||
itemHeight: 10,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
xAxisIndex: 0,
|
||||
start: 0,
|
||||
end: 50,
|
||||
zoomOnMouseWheel: "shift",
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
},
|
||||
{
|
||||
type: "slider",
|
||||
height: 6,
|
||||
bottom: "7%",
|
||||
show: true,
|
||||
start: 0,
|
||||
end: 50,
|
||||
handleSize: 5,
|
||||
handleStyle: {
|
||||
color: "#DCE2E8",
|
||||
},
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
showDetail: false,
|
||||
},
|
||||
],
|
||||
grid: {
|
||||
left: "10%",
|
||||
right: "5%",
|
||||
top: "15%",
|
||||
bottom: "25%",
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
data: names,
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "单位人员数",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(84,173,147,0.2)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#54AD93",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: unitPersonnelData,
|
||||
},
|
||||
{
|
||||
name: "相关方人员数",
|
||||
type: "bar",
|
||||
backgroundStyle: {
|
||||
color: "rgba(216, 229, 247, 0.55)",
|
||||
borderRadius: [8, 8, 0, 0],
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(72,117,231,0.2)",
|
||||
},
|
||||
{
|
||||
offset: 0,
|
||||
color: "#4875E7",
|
||||
},
|
||||
]),
|
||||
},
|
||||
barWidth: "10",
|
||||
data: relatedPartyPersonnelData,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
|
@ -1,140 +1,16 @@
|
|||
import { useMount } from "ahooks";
|
||||
import { useRef, useState } from "react";
|
||||
import SeamlessScroll from "zy-react-library/components/SeamlessScroll";
|
||||
import Title from "~/pages/Container/Map/components/Content/branchOffice/Title";
|
||||
import { initEcharts1, initEcharts2 } from "./echarts";
|
||||
import "./index.less";
|
||||
import AlarmHandlingPanel from "./AlarmHandlingPanel";
|
||||
import AlarmTypeChartPanel from "./AlarmTypeChartPanel";
|
||||
import ClosedAreaPersonnelPanel from "./ClosedAreaPersonnelPanel";
|
||||
import PersonnelLocationPanel from "./PersonnelLocationPanel";
|
||||
|
||||
/** 分公司人员模块仅负责按展示顺序组合业务区块。 */
|
||||
function RenYuan() {
|
||||
const chart1Instance = useRef(null);
|
||||
const main1Ref = useRef(null);
|
||||
const chart2Instance = useRef(null);
|
||||
const main2Ref = useRef(null);
|
||||
|
||||
const [block3List, setBlock3List] = useState([
|
||||
{ name: "张三", area: "A区", onlineStatus: 1 },
|
||||
{ name: "李四", area: "B区", onlineStatus: 1 },
|
||||
{ name: "王五", area: "C区", onlineStatus: 2 },
|
||||
{ name: "赵六", area: "D区", onlineStatus: 1 },
|
||||
{ name: "钱七", area: "E区", onlineStatus: 1 },
|
||||
{ name: "孙八", area: "F区", onlineStatus: 2 },
|
||||
{ name: "周九", area: "G区", onlineStatus: 1 },
|
||||
{ name: "吴十", area: "H区", onlineStatus: 1 },
|
||||
{ name: "郑一", area: "I区", onlineStatus: 2 },
|
||||
{ name: "王二", area: "J区", onlineStatus: 1 },
|
||||
]);
|
||||
const [block4List, setBlock4List] = useState([
|
||||
{ alarmContent: "SOS紧急告警", personnelInvolved: "张三", dispositionStatus: 1 },
|
||||
{ alarmContent: "静止/滞留告警", personnelInvolved: "李四", dispositionStatus: 2 },
|
||||
{ alarmContent: "电子围栏越界", personnelInvolved: "王五", dispositionStatus: 1 },
|
||||
{ alarmContent: "非授权区域停留", personnelInvolved: "赵六", dispositionStatus: 3 },
|
||||
{ alarmContent: "设备及信号类告警", personnelInvolved: "钱七", dispositionStatus: 1 },
|
||||
{ alarmContent: "聚集告警", personnelInvolved: "孙八", dispositionStatus: 2 },
|
||||
{ alarmContent: "单独作业告警", personnelInvolved: "周九", dispositionStatus: 1 },
|
||||
{ alarmContent: "超员/缺员告警", personnelInvolved: "吴十", dispositionStatus: 3 },
|
||||
{ alarmContent: "SOS紧急告警", personnelInvolved: "郑一", dispositionStatus: 1 },
|
||||
{ alarmContent: "静止/滞留告警", personnelInvolved: "王二", dispositionStatus: 2 },
|
||||
]);
|
||||
|
||||
useMount(() => {
|
||||
initEcharts1(main1Ref, chart1Instance, [
|
||||
{ name: "SOS紧急告警", value: "120" },
|
||||
{ name: "静止/滞留告警", value: "10" },
|
||||
{ name: "电子围栏越界", value: "10" },
|
||||
{ name: "非授权区域停留", value: "20" },
|
||||
{ name: "设备及信号类告警", value: "30" },
|
||||
{ name: "聚集告警", value: "40" },
|
||||
{ name: "单独作业告警", value: "50" },
|
||||
{ name: "超员/缺员告警", value: "60" },
|
||||
{ name: "已处置报警数/报警数", value: "10" },
|
||||
]);
|
||||
initEcharts2(main2Ref, chart2Instance, [
|
||||
{ name: "A区", unitPersonnelCount: 120, relatedPartyPersonnelCount: 85 },
|
||||
{ name: "B区", unitPersonnelCount: 95, relatedPartyPersonnelCount: 70 },
|
||||
{ name: "C区", unitPersonnelCount: 80, relatedPartyPersonnelCount: 60 },
|
||||
{ name: "D区", unitPersonnelCount: 150, relatedPartyPersonnelCount: 110 },
|
||||
{ name: "E区", unitPersonnelCount: 75, relatedPartyPersonnelCount: 55 },
|
||||
{ name: "F区", unitPersonnelCount: 110, relatedPartyPersonnelCount: 80 },
|
||||
{ name: "G区", unitPersonnelCount: 65, relatedPartyPersonnelCount: 45 },
|
||||
{ name: "H区", unitPersonnelCount: 140, relatedPartyPersonnelCount: 100 },
|
||||
{ name: "I区", unitPersonnelCount: 90, relatedPartyPersonnelCount: 65 },
|
||||
{ name: "J区", unitPersonnelCount: 125, relatedPartyPersonnelCount: 90 },
|
||||
]);
|
||||
|
||||
return () => {
|
||||
if (chart1Instance.current) {
|
||||
chart1Instance.current.dispose();
|
||||
chart1Instance.current = null;
|
||||
}
|
||||
if (chart2Instance.current) {
|
||||
chart2Instance.current.dispose();
|
||||
chart2Instance.current = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="branch_office_renyuan">
|
||||
<div className="block1">
|
||||
<Title title="报警类型" />
|
||||
<div className="options">
|
||||
<div ref={main1Ref} style={{ width: "100%", height: "250px" }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="block2">
|
||||
<Title title="封闭区域人员统计情况" />
|
||||
<div className="options">
|
||||
<div ref={main2Ref} style={{ width: "100%", height: "200px" }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="block3">
|
||||
<Title title="人员定位列表" />
|
||||
<div className="options">
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">人员姓名</div>
|
||||
<div className="td">所属区域</div>
|
||||
<div className="td">在线状态</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={block3List} step={0.5}>
|
||||
{block3List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.name}</div>
|
||||
<div className="td">{item.area}</div>
|
||||
<div className="td" style={{ color: item.onlineStatus === 1 ? "#1DB924" : "#fff" }}>{item.onlineStatus === 1 ? "在线" : "离线"}</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="block4">
|
||||
<Title title="告警处置情况" />
|
||||
<div className="options">
|
||||
<div className="table">
|
||||
<div className="tr">
|
||||
<div className="td">报警内容</div>
|
||||
<div className="td">涉及人员</div>
|
||||
<div className="td">处置情况</div>
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<SeamlessScroll list={block4List} step={0.5}>
|
||||
{block4List.map((item, index) => (
|
||||
<div key={index} className="tr">
|
||||
<div className="td">{item.alarmContent}</div>
|
||||
<div className="td">{item.personnelInvolved}</div>
|
||||
<div className="td" style={{ color: item.dispositionStatus === 1 ? "#1DB924" : item.dispositionStatus === 2 ? "#FF611C" : "#258FF1" }}>
|
||||
{item.dispositionStatus === 1 ? "已处置" : item.dispositionStatus === 2 ? "未处置" : "处置中"}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</SeamlessScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="branch-office-personnel">
|
||||
<AlarmTypeChartPanel />
|
||||
<ClosedAreaPersonnelPanel />
|
||||
<PersonnelLocationPanel />
|
||||
<AlarmHandlingPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,106 +0,0 @@
|
|||
.branch_office_renyuan {
|
||||
.block1 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.block2 {
|
||||
background-color: rgba(12, 28, 88, 0.4);
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.block3 {
|
||||
background-image: linear-gradient(to bottom,
|
||||
rgba(0, 0, 0, 0),
|
||||
rgba(0, 0, 0, 0.8));
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.table {
|
||||
margin-top: 5px;
|
||||
|
||||
.scroll {
|
||||
height: 100px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tr {
|
||||
margin-top: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block4 {
|
||||
background-image: linear-gradient(to bottom,
|
||||
rgba(0, 0, 0, 0),
|
||||
rgba(0, 0, 0, 0.8));
|
||||
margin-top: 10px;
|
||||
|
||||
.options {
|
||||
padding: 10px 15px;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(to bottom,
|
||||
rgba(58, 122, 149, 0),
|
||||
rgba(58, 122, 149, 1)) 1;
|
||||
border-top: none;
|
||||
|
||||
.table {
|
||||
margin-top: 5px;
|
||||
|
||||
.scroll {
|
||||
height: 100px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tr {
|
||||
margin-top: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
background-color: rgba(17, 51, 112, 0.8);
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import titleBgImg from "~/assets/images/map_bi/content/title_bg2.png";
|
||||
import "./index.less";
|
||||
|
||||
function Title(props) {
|
||||
return (
|
||||
<div className="map_content_branch_office_title_container" style={{ backgroundImage: `url(${titleBgImg})` }}>
|
||||
<div className="basic">
|
||||
<div className="label">{props.title}</div>
|
||||
</div>
|
||||
<div className="extra">{props.extra}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Title;
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
.map_content_branch_office_title_container {
|
||||
width: 100%;
|
||||
height: 41px;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.basic {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
padding-left: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.extra {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue