Browse Source

feat: 右侧面板

feature-v1.0.0
will 1 month ago
parent
commit
376baa967e
  1. BIN
      src/assets/card/safety-item-bg.png
  2. 2
      src/components.d.ts
  3. 22
      src/theme/index.scss
  4. 124
      src/views/Main/DailyPatrolCard/index.vue
  5. 176
      src/views/Main/RiskInspectionCard/index.vue
  6. 151
      src/views/Main/SafetyAppraise/index.vue
  7. 85
      src/views/Main/SafetyOverviewCard/index.vue
  8. 5
      src/views/Main/index.vue

BIN
src/assets/card/safety-item-bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

2
src/components.d.ts

@ -10,6 +10,8 @@ declare module 'vue' {
Card: typeof import('./components/Card/index.vue')['default'] Card: typeof import('./components/Card/index.vue')['default']
Dialog: typeof import('./components/Dialog/index.vue')['default'] Dialog: typeof import('./components/Dialog/index.vue')['default']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElOption: typeof import('element-plus/es')['ElOption']
ElSelect: typeof import('element-plus/es')['ElSelect']
Form: typeof import('./components/Form/index.vue')['default'] Form: typeof import('./components/Form/index.vue')['default']
InputNumber: typeof import('./components/Input/input-number.vue')['default'] InputNumber: typeof import('./components/Input/input-number.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']

22
src/theme/index.scss

@ -67,3 +67,25 @@ code {
color: #262626; color: #262626;
} }
.sy-water-cart-second-title {
height: 22px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0px 0px 0px 12px;
gap: 10px;
align-self: stretch;
border-width: 0px 0px 0px 2px;
border-style: solid;
border-color: #36b29e;
font-family: PingFang SC;
font-size: 16px;
font-weight: 500;
line-height: 22px;
letter-spacing: 0px;
font-variation-settings: "opsz" auto;
color: #262626;
}

124
src/views/Main/DailyPatrolCard/index.vue

@ -1,11 +1,131 @@
<template> <template>
<div></div> <div class="daily-patrol-card">
<div class="sy-water-cart-second-title">日常巡查</div>
<div class="echart-wrapper" ref="chartRef"></div>
<div class="appraise-progress">
<div class="tips">
<div>问题处理进度<span>23%</span></div>
</div>
<div class="progress">
<div class="progress-bar" style="width: 23%"></div>
</div>
</div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as echarts from "echarts";
defineOptions({ defineOptions({
name: "DailyPatrolCard", name: "DailyPatrolCard",
}); });
let chart: echarts.ECharts | undefined;
const chartRef = ref();
const handleResize = () => {
chart?.resize();
};
onMounted(() => {
chart = echarts.init(chartRef.value);
// Chart options
const option = {
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b}: {c} ({d}%)",
},
color: ["#4285F4", "#FF9F40", "#FFCD56", "#FF6384"],
series: [
{
name: "问题类型",
type: "pie",
radius: ["50%", "70%"],
avoidLabelOverlap: false,
label: {
show: false,
},
emphasis: {
label: {
show: false,
},
},
labelLine: {
show: false,
},
data: [
{ value: 545, name: "一般" },
{ value: 21, name: "重大" },
{ value: 300, name: "较大" },
{ value: 64, name: "紧急" },
],
},
],
};
// Set options and render chart
chart.setOption(option);
window.addEventListener("resize", handleResize);
});
onBeforeUnmount(() => {
chart?.dispose();
window.removeEventListener("resize", handleResize);
});
</script> </script>
<style scoped></style> <style scoped lang="less">
.daily-patrol-card {
width: 100%;
display: flex;
flex-direction: column;
gap: 16px;
.echart-wrapper {
width: 100%;
height: 164px;
}
.appraise-progress {
width: 100%;
display: flex;
flex-direction: column;
gap: 16px;
.tips {
display: flex;
align-items: center;
gap: 12px;
justify-content: flex-start;
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 0px;
font-variation-settings: "opsz" auto;
color: rgba(0, 0, 0, 0.55);
span {
font-family: DIN;
font-size: 16px;
font-weight: bold;
line-height: 22px;
letter-spacing: 0px;
font-variation-settings: "opsz" auto;
color: #28ce8e;
}
}
.progress {
width: 100%;
background: rgba(255, 255, 255, 0.4);
height: 24px;
border-radius: 12px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
overflow: hidden;
.progress-bar {
height: 100%;
background: #28ce8e;
}
}
}
}
</style>

176
src/views/Main/RiskInspectionCard/index.vue

@ -1,11 +1,183 @@
<template> <template>
<div></div> <div class="risk-inspection-card">
<div class="sy-water-cart-second-title">病险核查</div>
<div class="inspection-content">
<div class="left">
<div class="title">病险核查问题</div>
<div class="echart-wrapper" ref="problemEchartRef"></div>
</div>
<div class="right">
<div class="title">病险核查任务</div>
<div class="echart-wrapper" ref="questEchartRef"></div>
</div>
</div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as echarts from "echarts";
defineOptions({ defineOptions({
name: "RiskInspectionCard", name: "RiskInspectionCard",
}); });
const problemEchartRef = ref();
const questEchartRef = ref();
let leftChart: echarts.ECharts | undefined;
let rightChart: echarts.ECharts | undefined;
const handleResize = () => {
leftChart?.resize();
rightChart?.resize();
};
onMounted(() => {
leftChart = echarts.init(problemEchartRef.value);
// Chart options for the left side (nested pie)
const leftOption = {
tooltip: {
trigger: "item",
formatter: "{b}: {c}",
},
color: ["#FFCD56", "#4285F4"],
series: [
{
type: "pie",
radius: ["65%", "90%"],
avoidLabelOverlap: false,
label: {
show: false,
position: "center",
},
emphasis: {
label: {
show: false,
},
},
labelLine: {
show: false,
},
data: [
{ value: 98, name: "工程总数", itemStyle: { color: "#FFCD56" } },
{ value: 0, name: "", itemStyle: { color: "transparent" } },
],
},
{
type: "pie",
radius: ["40%", "60%"],
avoidLabelOverlap: false,
label: {
show: false,
position: "center",
},
emphasis: {
label: {
show: false,
},
},
labelLine: {
show: false,
},
data: [
{ value: 56, name: "问题数", itemStyle: { color: "#4285F4" } },
{ value: 42, name: "", itemStyle: { color: "transparent" } },
],
},
],
};
// Set options and render left chart
leftChart.setOption(leftOption);
rightChart = echarts.init(questEchartRef.value);
// Chart options for the right side (liquidFill)
const rightOption = {
series: [
{
type: "liquidFill",
radius: "80%",
data: [0.165],
label: {
normal: {
textStyle: {
fontSize: 35,
fontWeight: "bold",
color: "#000",
},
position: ["50%", "45%"],
formatter: function () {
return "16.5%";
},
},
},
outline: {
show: true,
borderDistance: 0,
itemStyle: {
borderWidth: 1,
borderColor: "#20C997",
},
},
color: ["#20C997"],
backgroundStyle: {
color: "rgba(32, 201, 151, 0.1)",
},
itemStyle: {
opacity: 0.7,
},
emphasis: {
itemStyle: {
opacity: 0.9,
},
},
},
],
};
// Set options and render right chart
rightChart.setOption(rightOption);
window.addEventListener("resize", handleResize);
});
onBeforeUnmount(() => {
leftChart?.dispose();
rightChart?.dispose();
window.removeEventListener("resize", handleResize);
});
</script> </script>
<style scoped></style> <style scoped lang="less">
.risk-inspection-card {
width: 100%;
display: flex;
flex-direction: column;
gap: 16px;
.inspection-content {
display: flex;
flex-direction: row;
gap: 16px;
.left,
.right {
width: 50%;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
.title {
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: normal;
line-height: 23.4px;
text-align: right;
display: flex;
align-items: center;
letter-spacing: 0px;
color: #000000;
}
.echart-wrapper {
height: 192px - 24px - 12px;
width: 170px;
}
}
}
}
</style>

151
src/views/Main/SafetyAppraise/index.vue

@ -0,0 +1,151 @@
<template>
<div class="safety-appraise">
<div class="sy-water-cart-second-title">安全鉴定</div>
<div class="appraise-wrapper">
<div class="appraise-item">
<div class="count total">456</div>
<div class="name">任务数</div>
</div>
<div class="appraise-item">
<div class="count wait">400</div>
<div class="name">待鉴定</div>
</div>
<div class="appraise-item">
<div class="count ok">56</div>
<div class="name">已鉴定</div>
</div>
</div>
<div class="appraise-progress">
<div class="tips">
<div>已完成<span class="ok">23%</span></div>
<div>进行中<span class="in">23%</span></div>
<div>超期未鉴定<span class="overdue">23%</span></div>
</div>
<div class="progress">
<div class="progress-bar ok" style="width: 23%"></div>
<div class="progress-bar in" style="width: 23%"></div>
<div class="progress-bar overdue" style="width: 23%"></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
defineOptions({
name: "safety-appraise",
});
</script>
<style scoped lang="less">
.safety-appraise {
width: 100%;
display: flex;
flex-direction: column;
gap: 16px;
.appraise-wrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.appraise-item {
width: 104px;
height: 119px;
background: url("@/assets/card/safety-item-bg.png") no-repeat;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-bottom: 16px;
.name {
font-family: Source Han Sans;
font-size: 14px;
font-weight: normal;
line-height: 18px;
text-align: center;
letter-spacing: 0em;
font-variation-settings: "opsz" auto;
font-feature-settings: "kern" on;
color: #ffffff;
}
.count {
font-family: DIN;
font-size: 28px;
font-weight: bold;
line-height: normal;
letter-spacing: 0em;
&.total {
color: #7be4ff;
}
&.wait {
color: #ffc552;
}
&.ok {
color: #46ffe1;
}
}
}
}
.appraise-progress {
width: 100%;
display: flex;
flex-direction: column;
gap: 16px;
.tips {
display: flex;
align-items: center;
gap: 12px;
justify-content: flex-start;
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 0px;
font-variation-settings: "opsz" auto;
color: rgba(0, 0, 0, 0.55);
span {
font-family: DIN;
font-size: 16px;
font-weight: bold;
line-height: 22px;
letter-spacing: 0px;
font-variation-settings: "opsz" auto;
&.ok {
color: #28ce8e;
}
&.in {
color: #faad10;
}
&.overdue {
color: #f13939;
}
}
}
.progress {
width: 100%;
background: rgba(255, 255, 255, 0.4);
height: 24px;
border-radius: 12px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
overflow: hidden;
.progress-bar {
height: 100%;
&.ok {
background: #28ce8e;
}
&.overdue {
background: #f13939;
}
&.in {
background: #faad10;
}
}
}
}
}
</style>

85
src/views/Main/SafetyOverviewCard/index.vue

@ -1,11 +1,92 @@
<template> <template>
<div></div> <div class="safety-overview-card">
<div class="sy-water-cart-title">
安全监查情况
<el-select class="sy-water-cart-title-select" size="small">
<el-option label="近7日" value="1"></el-option>
</el-select>
</div>
<SafetyAppraise />
<RiskInspectionCard />
<DailyPatrolCard />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import SafetyAppraise from "../SafetyAppraise/index.vue";
import RiskInspectionCard from "../RiskInspectionCard/index.vue";
import DailyPatrolCard from "../DailyPatrolCard/index.vue";
defineOptions({ defineOptions({
name: "SafetyOverviewCard", name: "SafetyOverviewCard",
}); });
</script> </script>
<style scoped></style> <style scoped lang="less">
.safety-overview-card {
width: 100%;
display: flex;
flex-direction: column;
gap: 16px;
:deep(.sy-water-cart-title-select) {
width: 100px;
background: #36b29e;
height: 28px;
line-height: 28px;
color: #fff;
.sy-input--small .sy-input__wrapper {
padding: 1px 7px;
height: 28px;
.sy-select__caret {
color: #fff;
}
}
::-webkit-input-placeholder {
color: #fff;
}
}
.appraise-wrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.appraise-item {
width: 104px;
height: 119px;
background: url("@/assets/card/safety-item-bg.png") no-repeat;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-bottom: 16px;
.name {
font-family: Source Han Sans;
font-size: 14px;
font-weight: normal;
line-height: 18px;
text-align: center;
letter-spacing: 0em;
font-variation-settings: "opsz" auto;
font-feature-settings: "kern" on;
color: #ffffff;
}
.count {
font-family: DIN;
font-size: 28px;
font-weight: bold;
line-height: normal;
letter-spacing: 0em;
&.total {
color: #7be4ff;
}
&.wait {
color: #ffc552;
}
&.ok {
color: #46ffe1;
}
}
}
}
}
</style>

5
src/views/Main/index.vue

@ -9,8 +9,6 @@
<RightPanel> <RightPanel>
<Drawer style="width: 460px"> <Drawer style="width: 460px">
<SafetyOverviewCard /> <SafetyOverviewCard />
<RiskInspectionCard />
<DailyPatrolCard />
</Drawer> </Drawer>
</RightPanel> </RightPanel>
<BottomPanel></BottomPanel> <BottomPanel></BottomPanel>
@ -26,8 +24,7 @@ import ProjectCountCard from "./ProjectCountCard/index.vue";
import MonitoringCard from "./MonitoringCard/index.vue"; import MonitoringCard from "./MonitoringCard/index.vue";
import InspectionCard from "./InspectionCard/index.vue"; import InspectionCard from "./InspectionCard/index.vue";
import SafetyOverviewCard from "./SafetyOverviewCard/index.vue"; import SafetyOverviewCard from "./SafetyOverviewCard/index.vue";
import RiskInspectionCard from "./RiskInspectionCard/index.vue";
import DailyPatrolCard from "./DailyPatrolCard/index.vue";
import Map from "./Map/index.vue"; import Map from "./Map/index.vue";
defineOptions({ defineOptions({
name: "main", name: "main",

Loading…
Cancel
Save