首页UI优化

This commit is contained in:
chenlin
2025-12-30 17:07:46 +08:00
parent 8e654df0db
commit 9de42afb45
3 changed files with 998 additions and 286 deletions

View File

@@ -38,13 +38,30 @@
<Echart :options="outsourcingChartOption" width="100%" height="200px" /> <Echart :options="outsourcingChartOption" width="100%" height="200px" />
</div> </div>
<div class="region-distribution"> <div class="region-distribution">
<div class="distribution-title">区域分布</div> <div class="distribution-title">区域人数分布</div>
<div class="distribution-list"> <div class="grid-wrapper">
<div class="distribution-item" v-for="item in outsourcingDistribution" :key="item.region"> <!-- 第一列区域名称 -->
<span class="dot" :style="{ backgroundColor: item.color }"></span> <div class="grid-column">
<span class="region-name">{{ item.region }}</span> <div class="grid-header empty-header"></div>
<span class="region-count">{{ item.count }}</span> <div class="grid-park-name" v-for="item in outsourcingDistribution" :key="'area-' + item.region">
<span class="region-percent">({{ item.percent }})</span> {{ item.region }}
</div>
</div>
<!-- 人数列 -->
<div class="grid-column">
<div class="grid-header">人数</div>
<div class="grid-number" v-for="item in outsourcingDistribution"
:key="'count-' + item.region">
{{ item.count }}
</div>
</div>
<!-- 百分比列 -->
<div class="grid-column">
<div class="grid-header">占比</div>
<div class="grid-number" v-for="item in outsourcingDistribution"
:key="'percent-' + item.region">
{{ item.percent }}
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -66,27 +83,46 @@
</div> </div>
<div class="risk-distribution-table"> <div class="risk-distribution-table">
<div class="distribution-title">区域风险分布</div> <div class="distribution-title">区域风险分布</div>
<div class="table-wrapper"> <div class="grid-wrapper">
<table class="risk-table"> <!-- 第一列区域名称 -->
<thead> <div class="grid-column">
<tr> <div class="grid-header empty-header"></div>
<th>区域</th> <div class="grid-park-name" v-for="item in areaRiskDistribution" :key="'area-' + item.area">
<th></th> {{ item.area }}
<th>一般</th> </div>
<th>较大</th> </div>
<th>重大</th> <!-- 低列 -->
</tr> <div class="grid-column">
</thead> <div class="grid-header status-low"></div>
<tbody> <div class="grid-number status-low" v-for="item in areaRiskDistribution"
<tr v-for="item in areaRiskDistribution" :key="item.area"> :key="'low-' + item.area">
<td>{{ item.area }}</td> {{ item.low || '0' }}
<td>{{ item.low || '0' }}</td> </div>
<td>{{ item.general || '0' }}</td> </div>
<td>{{ item.moderate || '0' }}</td> <!-- 一般列 -->
<td>{{ item.major || '0' }}</td> <div class="grid-column">
</tr> <div class="grid-header status-general">一般</div>
</tbody> <div class="grid-number status-general" v-for="item in areaRiskDistribution"
</table> :key="'general-' + item.area">
{{ item.general || '0' }}
</div>
</div>
<!-- 较大列 -->
<div class="grid-column">
<div class="grid-header status-moderate">较大</div>
<div class="grid-number status-moderate" v-for="item in areaRiskDistribution"
:key="'moderate-' + item.area">
{{ item.moderate || '0' }}
</div>
</div>
<!-- 重大列 -->
<div class="grid-column">
<div class="grid-header status-major">重大</div>
<div class="grid-number status-major" v-for="item in areaRiskDistribution"
:key="'major-' + item.area">
{{ item.major || '0' }}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -107,7 +143,10 @@
</div> </div>
<div class="rectification-status-grid"> <div class="rectification-status-grid">
<div class="distribution-title">区域整改状态</div> <div class="distribution-title">区域整改状态</div>
<div class="grid-wrapper"> <div v-if="areaRectificationStatus.length === 0" class="empty-data-tip">
暂无数据
</div>
<div v-else class="grid-wrapper">
<!-- 第一列区域名称 --> <!-- 第一列区域名称 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header empty-header"></div> <div class="grid-header empty-header"></div>
@@ -118,22 +157,25 @@
<!-- 已逾期列 --> <!-- 已逾期列 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-overdue">已逾期</div> <div class="grid-header status-overdue">已逾期</div>
<div class="grid-number status-overdue" v-for="item in areaRectificationStatus" :key="'overdue-' + item.area"> <div class="grid-number status-overdue" v-for="item in areaRectificationStatus"
{{ item.overdue }} :key="'overdue-' + item.area">
{{ item.overdue ?? 0 }}
</div> </div>
</div> </div>
<!-- 处理中列 --> <!-- 处理中列 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-processing">处理中</div> <div class="grid-header status-processing">处理中</div>
<div class="grid-number status-processing" v-for="item in areaRectificationStatus" :key="'processing-' + item.area"> <div class="grid-number status-processing" v-for="item in areaRectificationStatus"
{{ item.processing }} :key="'processing-' + item.area">
{{ item.processing ?? 0 }}
</div> </div>
</div> </div>
<!-- 已处理列 --> <!-- 已处理列 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-processed">已处理</div> <div class="grid-header status-processed">已处理</div>
<div class="grid-number status-processed" v-for="item in areaRectificationStatus" :key="'processed-' + item.area"> <div class="grid-number status-processed" v-for="item in areaRectificationStatus"
{{ item.processed }} :key="'processed-' + item.area">
{{ item.processed ?? 0 }}
</div> </div>
</div> </div>
</div> </div>
@@ -336,22 +378,23 @@ const dateRange = ref(getInitialDateRange())
// 应急预案:/yayl/table/view/1966394259751907330 // 应急预案:/yayl/table/view/1966394259751907330
// 安全培训:/pxks/table/view/1968225010550091777 // 安全培训:/pxks/table/view/1968225010550091777
const openOutsourcingManagement = () => { const openOutsourcingManagement = () => {
window.open('/person/table/view/1959187451673116674', '_blank') // 不打开新标签页
router.push('/person/table/view/1959187451673116674')
} }
const openRiskManagement = () => { const openRiskManagement = () => {
window.open('/fx/table/view/1978723750599790594', '_blank') router.push('/fx/table/view/1978723750599790594')
} }
const openHiddenDangerManagement = () => { const openHiddenDangerManagement = () => {
window.open('/fx/table/view/1963446160885366786', '_blank') router.push('/fx/table/view/1963446160885366786')
} }
const openHighRiskManagement = () => { const openHighRiskManagement = () => {
window.open('/low/table/view/1964253329070571521', '_blank') router.push('/low/table/view/1964253329070571521')
} }
const openEmergencyPlanManagement = () => { const openEmergencyPlanManagement = () => {
window.open('/yayl/table/view/1966394259751907330', '_blank') router.push('/yayl/table/view/1966394259751907330')
} }
const openTrainingManagement = () => { const openTrainingManagement = () => {
window.open('/pxks/table/view/1968225010550091777', '_blank') router.push('/pxks/table/view/1968225010550091777')
} }
// 外协管理数据 // 外协管理数据
@@ -611,11 +654,14 @@ const riskChartOption = computed<EChartsOption>(() => {
const hiddenDangerChartOption = computed<EChartsOption>(() => { const hiddenDangerChartOption = computed<EChartsOption>(() => {
// 提取日期和对应的数据 // 提取日期和对应的数据
const dates = hiddenDangerTrend.value.map(item => item.date) const dates = hiddenDangerTrend.value.map(item => item.date)
const generalData = hiddenDangerTrend.value.map(item => item.general) const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0)
const majorData = hiddenDangerTrend.value.map(item => item.major) const majorData = hiddenDangerTrend.value.map(item => item.major ?? 0)
// 判断是否为空数据
const isEmpty = dates.length === 0 || (generalData.every(v => v === 0) && majorData.every(v => v === 0))
// 计算Y轴最大值向上取整到最近的10的倍数 // 计算Y轴最大值向上取整到最近的10的倍数
const maxValue = Math.max( const maxValue = isEmpty ? 10 : Math.max(
...generalData, ...generalData,
...majorData, ...majorData,
10 // 最小值为10避免图表显示过小 10 // 最小值为10避免图表显示过小
@@ -646,18 +692,42 @@ const hiddenDangerChartOption = computed<EChartsOption>(() => {
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: dates.length > 0 ? dates : [] data: dates.length > 0 ? dates : [],
show: !isEmpty
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
max: yAxisMax max: yAxisMax,
show: !isEmpty
}, },
series: [ graphic: isEmpty ? [
{
type: 'group',
left: 'center',
top: 'center',
children: [
{
type: 'text',
z: 100,
left: 'center',
top: 'center',
style: {
text: '暂无数据',
fontSize: 16,
fontWeight: 'normal',
fill: '#9ca3af',
textAlign: 'center'
}
}
]
}
] : [],
series: isEmpty ? [] : [
{ {
name: '一般隐患', name: '一般隐患',
type: 'line', type: 'line',
smooth: true, smooth: true,
data: generalData.length > 0 ? generalData : [], data: generalData,
itemStyle: { color: '#f59e0b' }, itemStyle: { color: '#f59e0b' },
lineStyle: { color: '#f59e0b', width: 2 }, lineStyle: { color: '#f59e0b', width: 2 },
areaStyle: { areaStyle: {
@@ -678,7 +748,7 @@ const hiddenDangerChartOption = computed<EChartsOption>(() => {
name: '重大隐患', name: '重大隐患',
type: 'line', type: 'line',
smooth: true, smooth: true,
data: majorData.length > 0 ? majorData : [], data: majorData,
itemStyle: { color: '#ef4444' }, itemStyle: { color: '#ef4444' },
lineStyle: { color: '#ef4444', width: 2 }, lineStyle: { color: '#ef4444', width: 2 },
areaStyle: { areaStyle: {
@@ -1540,15 +1610,15 @@ onMounted(async () => {
color: white; color: white;
user-select: none; user-select: none;
font-weight: 600; font-weight: 600;
span { gap: 5px;
margin-left: 8px;
font-size: 18px;
color: #6b7280;
}
&:hover { &:hover {
background: #e5e7eb; background: #2563eb;
border-color: #d1d5db; }
span {
font-size: 18px;
line-height: 1;
} }
&:active { &:active {
@@ -1616,6 +1686,7 @@ onMounted(async () => {
} }
@media (max-width: 1200px) { @media (max-width: 1200px) {
.high-risk-top, .high-risk-top,
.emergency-plan-top { .emergency-plan-top {
gap: 10px; gap: 10px;
@@ -1634,6 +1705,7 @@ onMounted(async () => {
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.high-risk-top, .high-risk-top,
.emergency-plan-top { .emergency-plan-top {
flex-direction: column; flex-direction: column;
@@ -1825,6 +1897,14 @@ onMounted(async () => {
font-weight: 600; font-weight: 600;
color: #374151; color: #374151;
margin-bottom: 12px; margin-bottom: 12px;
display: flex;
align-items: center;
justify-content: space-between;
span {
font-size: 14px;
font-weight: 600;
color: #374151;
}
} }
.distribution-list { .distribution-list {
@@ -1868,6 +1948,13 @@ onMounted(async () => {
// 网格样式 // 网格样式
.rectification-status-grid { .rectification-status-grid {
.empty-data-tip {
text-align: center;
padding: 40px 0;
color: #9ca3af;
font-size: 14px;
}
.grid-wrapper { .grid-wrapper {
display: flex; display: flex;
gap: 0; gap: 0;
@@ -1956,32 +2043,169 @@ onMounted(async () => {
} }
} }
.table-wrapper { // 风险管理网格样式(与隐患管理一致)
overflow-x: auto; .risk-distribution-table {
.grid-wrapper {
display: flex;
gap: 0;
justify-content: flex-start;
}
.grid-column {
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
&:first-child {
align-items: flex-start;
margin-right: 20px;
flex: 0 0 auto;
min-width: 80px;
}
&:not(:first-child) {
flex: 1;
min-width: 60px;
}
}
.grid-header {
font-size: 14px;
font-weight: bold;
margin-bottom: 12px;
height: 20px;
line-height: 20px;
&.empty-header {
visibility: hidden;
}
&.status-low {
color: #117cee;
}
&.status-general {
color: #fbde28;
}
&.status-moderate {
color: #ed740c;
}
&.status-major {
color: #df2a3f;
}
}
.grid-park-name {
font-size: 13px;
color: #333;
margin-bottom: 8px;
text-align: left;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
}
.grid-number {
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
text-align: center;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
&.status-low {
color: #117cee;
}
&.status-general {
color: #fbde28;
}
&.status-moderate {
color: #ed740c;
}
&.status-major {
color: #df2a3f;
}
}
} }
.risk-table { // 外协管理网格样式(与隐患管理一致)
width: 100%; .region-distribution {
border-collapse: collapse; .grid-wrapper {
font-size: 13px; display: flex;
gap: 0;
thead { justify-content: flex-start;
background-color: #f9fafb;
} }
th, td { .grid-column {
padding: 8px; display: flex;
text-align: left; flex-direction: column;
border-bottom: 1px solid #e5e7eb; align-items: center;
min-width: 0;
&:first-child {
align-items: flex-start;
margin-right: 20px;
flex: 0 0 auto;
min-width: 80px;
} }
th { &:not(:first-child) {
flex: 1;
min-width: 60px;
}
}
.grid-header {
font-size: 14px;
font-weight: bold; font-weight: bold;
color: #333; margin-bottom: 12px;
height: 20px;
line-height: 20px;
color: #374151;
&.empty-header {
visibility: hidden;
}
} }
td { .grid-park-name {
color: #666; font-size: 13px;
color: #333;
margin-bottom: 8px;
text-align: left;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
}
.grid-number {
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
text-align: center;
height: 24px;
line-height: 24px;
color: #1f2937;
&:last-child {
margin-bottom: 0;
}
} }
} }
@@ -2060,12 +2284,10 @@ onMounted(async () => {
left: 0; left: 0;
bottom: 0; bottom: 0;
right: 0; right: 0;
background: linear-gradient( background: linear-gradient(90deg,
90deg,
transparent 0%, transparent 0%,
rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 50%,
transparent 100% transparent 100%);
);
animation: shimmer 2s infinite; animation: shimmer 2s infinite;
} }
} }
@@ -2084,6 +2306,7 @@ onMounted(async () => {
0% { 0% {
transform: translateX(-100%); transform: translateX(-100%);
} }
100% { 100% {
transform: translateX(100%); transform: translateX(100%);
} }

View File

@@ -41,13 +41,30 @@
<Echart :options="outsourcingChartOption" width="100%" height="200px" /> <Echart :options="outsourcingChartOption" width="100%" height="200px" />
</div> </div>
<div class="region-distribution"> <div class="region-distribution">
<div class="distribution-title">园区分布</div> <div class="distribution-title">园区人数分布</div>
<div class="distribution-list"> <div class="grid-wrapper">
<div class="distribution-item" v-for="item in outsourcingDistribution" :key="item.region"> <!-- 第一列园区名称 -->
<span class="dot" :style="{ backgroundColor: item.color }"></span> <div class="grid-column">
<span class="region-name">{{ item.region }}</span> <div class="grid-header empty-header"></div>
<span class="region-count">{{ item.count }}</span> <div class="grid-park-name" v-for="item in outsourcingDistribution" :key="'area-' + item.region">
<span class="region-percent">({{ item.percent }})</span> {{ item.region }}
</div>
</div>
<!-- 人数列 -->
<div class="grid-column">
<div class="grid-header">人数</div>
<div class="grid-number" v-for="item in outsourcingDistribution"
:key="'count-' + item.region">
{{ item.count }}
</div>
</div>
<!-- 占比列 -->
<div class="grid-column">
<div class="grid-header">占比</div>
<div class="grid-number" v-for="item in outsourcingDistribution"
:key="'percent-' + item.region">
{{ item.percent }}
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -69,27 +86,46 @@
</div> </div>
<div class="risk-distribution-table"> <div class="risk-distribution-table">
<div class="distribution-title">园区风险分布</div> <div class="distribution-title">园区风险分布</div>
<div class="table-wrapper"> <div class="grid-wrapper">
<table class="risk-table"> <!-- 第一列园区名称 -->
<thead> <div class="grid-column">
<tr> <div class="grid-header empty-header"></div>
<th>园区</th> <div class="grid-park-name" v-for="item in parkRiskDistribution" :key="'area-' + item.park">
<th></th> {{ item.park }}
<th>一般</th> </div>
<th>较大</th> </div>
<th>重大</th> <!-- 低列 -->
</tr> <div class="grid-column">
</thead> <div class="grid-header status-low"></div>
<tbody> <div class="grid-number status-low" v-for="item in parkRiskDistribution"
<tr v-for="item in parkRiskDistribution" :key="item.park"> :key="'low-' + item.park">
<td>{{ item.park }}</td> {{ item.low || '0' }}
<td>{{ item.low || '' }}</td> </div>
<td>{{ item.general }}</td> </div>
<td>{{ item.moderate }}</td> <!-- 一般列 -->
<td>{{ item.major }}</td> <div class="grid-column">
</tr> <div class="grid-header status-general">一般</div>
</tbody> <div class="grid-number status-general" v-for="item in parkRiskDistribution"
</table> :key="'general-' + item.park">
{{ item.general || '0' }}
</div>
</div>
<!-- 较大列 -->
<div class="grid-column">
<div class="grid-header status-moderate">较大</div>
<div class="grid-number status-moderate" v-for="item in parkRiskDistribution"
:key="'moderate-' + item.park">
{{ item.moderate || '0' }}
</div>
</div>
<!-- 重大列 -->
<div class="grid-column">
<div class="grid-header status-major">重大</div>
<div class="grid-number status-major" v-for="item in parkRiskDistribution"
:key="'major-' + item.park">
{{ item.major || '0' }}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -110,7 +146,10 @@
</div> </div>
<div class="rectification-status-grid"> <div class="rectification-status-grid">
<div class="distribution-title">园区整改状态</div> <div class="distribution-title">园区整改状态</div>
<div class="grid-wrapper"> <div v-if="parkRectificationStatus.length === 0" class="empty-data-tip">
暂无数据
</div>
<div v-else class="grid-wrapper">
<!-- 第一列园区名称 --> <!-- 第一列园区名称 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header empty-header"></div> <div class="grid-header empty-header"></div>
@@ -122,21 +161,21 @@
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-overdue">已逾期</div> <div class="grid-header status-overdue">已逾期</div>
<div class="grid-number status-overdue" v-for="item in parkRectificationStatus" :key="'overdue-' + item.park"> <div class="grid-number status-overdue" v-for="item in parkRectificationStatus" :key="'overdue-' + item.park">
{{ item.overdue }} {{ item.overdue ?? 0 }}
</div> </div>
</div> </div>
<!-- 处理中列 --> <!-- 处理中列 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-processing">处理中</div> <div class="grid-header status-processing">处理中</div>
<div class="grid-number status-processing" v-for="item in parkRectificationStatus" :key="'processing-' + item.park"> <div class="grid-number status-processing" v-for="item in parkRectificationStatus" :key="'processing-' + item.park">
{{ item.processing }} {{ item.processing ?? 0 }}
</div> </div>
</div> </div>
<!-- 已处理列 --> <!-- 已处理列 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-processed">已处理</div> <div class="grid-header status-processed">已处理</div>
<div class="grid-number status-processed" v-for="item in parkRectificationStatus" :key="'processed-' + item.park"> <div class="grid-number status-processed" v-for="item in parkRectificationStatus" :key="'processed-' + item.park">
{{ item.processed }} {{ item.processed ?? 0 }}
</div> </div>
</div> </div>
</div> </div>
@@ -329,22 +368,22 @@ const parkOption = ref<ParkItem[]>([])
// 应急预案:/yayl/table/view/1966394259751907330 // 应急预案:/yayl/table/view/1966394259751907330
// 安全培训:/pxks/table/view/1968225010550091777 // 安全培训:/pxks/table/view/1968225010550091777
const openOutsourcingManagement = () => { const openOutsourcingManagement = () => {
window.open('/person/table/view/1959187451673116674', '_blank') router.push('/person/table/view/1959187451673116674')
} }
const openRiskManagement = () => { const openRiskManagement = () => {
window.open('/fx/table/view/1978723750599790594', '_blank') router.push('/fx/table/view/1978723750599790594')
} }
const openHiddenDangerManagement = () => { const openHiddenDangerManagement = () => {
window.open('/fx/table/view/1963446160885366786', '_blank') router.push('/fx/table/view/1963446160885366786')
} }
const openHighRiskManagement = () => { const openHighRiskManagement = () => {
window.open('/low/table/view/1964253329070571521', '_blank') router.push('/low/table/view/1964253329070571521')
} }
const openEmergencyPlanManagement = () => { const openEmergencyPlanManagement = () => {
window.open('/yayl/table/view/1966394259751907330', '_blank') router.push('/yayl/table/view/1966394259751907330')
} }
const openTrainingManagement = () => { const openTrainingManagement = () => {
window.open('/pxks/table/view/1968225010550091777', '_blank') router.push('/pxks/table/view/1968225010550091777')
} }
// 时间选择相关 - 默认当前月起止,如果路由中有日期范围参数则使用 // 时间选择相关 - 默认当前月起止,如果路由中有日期范围参数则使用
const getCurrentMonthRange = () => { const getCurrentMonthRange = () => {
@@ -1130,8 +1169,11 @@ const riskChartOption = computed<EChartsOption>(() => {
// 隐患管理折线图配置 // 隐患管理折线图配置
const hiddenDangerChartOption = computed<EChartsOption>(() => { const hiddenDangerChartOption = computed<EChartsOption>(() => {
const dates = hiddenDangerTrend.value.map(item => item.date) const dates = hiddenDangerTrend.value.map(item => item.date)
const generalData = hiddenDangerTrend.value.map(item => item.general) const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0)
const majorData = hiddenDangerTrend.value.map(item => item.major) const majorData = hiddenDangerTrend.value.map(item => item.major ?? 0)
// 判断是否为空数据
const isEmpty = dates.length === 0 || (generalData.every(v => v === 0) && majorData.every(v => v === 0))
return { return {
tooltip: { trigger: 'axis' }, tooltip: { trigger: 'axis' },
@@ -1139,14 +1181,40 @@ const hiddenDangerChartOption = computed<EChartsOption>(() => {
data: ['一般隐患', '重大隐患'], data: ['一般隐患', '重大隐患'],
top: 10 top: 10
}, },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, grid: { left: '3%', right: '4%', bottom: '3%', top: '12%', containLabel: true },
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: dates data: dates,
show: !isEmpty
}, },
yAxis: { type: 'value' }, yAxis: {
series: [ type: 'value',
show: !isEmpty
},
graphic: isEmpty ? [
{
type: 'group',
left: 'center',
top: 'center',
children: [
{
type: 'text',
z: 100,
left: 'center',
top: 'center',
style: {
text: '暂无数据',
fontSize: 16,
fontWeight: 'normal',
fill: '#9ca3af',
textAlign: 'center'
}
}
]
}
] : [],
series: isEmpty ? [] : [
{ {
name: '一般隐患', name: '一般隐患',
type: 'line', type: 'line',
@@ -1559,6 +1627,14 @@ onMounted(() => {
font-weight: bold; font-weight: bold;
color: #333; color: #333;
margin-bottom: 10px; margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
span {
font-size: 14px;
font-weight: 600;
color: #374151;
}
} }
.distribution-list { .distribution-list {
@@ -1595,11 +1671,104 @@ onMounted(() => {
color: #999; color: #999;
} }
.table-wrapper { // 风险管理网格样式(与隐患管理一致)
overflow-x: auto; .risk-distribution-table {
.grid-wrapper {
display: flex;
gap: 0;
justify-content: flex-start;
}
.grid-column {
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
&:first-child {
align-items: flex-start;
margin-right: 20px;
flex: 0 0 auto;
min-width: 80px;
}
&:not(:first-child) {
flex: 1;
min-width: 60px;
}
}
.grid-header {
font-size: 14px;
font-weight: bold;
margin-bottom: 12px;
height: 20px;
line-height: 20px;
&.empty-header {
visibility: hidden;
}
&.status-low {
color: #117cee;
}
&.status-general {
color: #fbde28;
}
&.status-moderate {
color: #ed740c;
}
&.status-major {
color: #df2a3f;
}
}
.grid-park-name {
font-size: 13px;
color: #333;
margin-bottom: 8px;
text-align: left;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
}
.grid-number {
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
text-align: center;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
&.status-low {
color: #117cee;
}
&.status-general {
color: #fbde28;
}
&.status-moderate {
color: #ed740c;
}
&.status-major {
color: #df2a3f;
}
}
} }
.risk-table,
.status-table { .status-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
@@ -1627,6 +1796,13 @@ onMounted(() => {
// 九宫格样式 // 九宫格样式
.rectification-status-grid { .rectification-status-grid {
.empty-data-tip {
text-align: center;
padding: 40px 0;
color: #9ca3af;
font-size: 14px;
}
.grid-wrapper { .grid-wrapper {
display: flex; display: flex;
gap: 0; gap: 0;
@@ -1715,6 +1891,74 @@ onMounted(() => {
} }
} }
// 外协管理网格样式(与隐患管理一致)
.region-distribution {
.grid-wrapper {
display: flex;
gap: 0;
justify-content: flex-start;
}
.grid-column {
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
&:first-child {
align-items: flex-start;
margin-right: 20px;
flex: 0 0 auto;
min-width: 80px;
}
&:not(:first-child) {
flex: 1;
min-width: 60px;
}
}
.grid-header {
font-size: 14px;
font-weight: bold;
margin-bottom: 12px;
height: 20px;
line-height: 20px;
color: #374151;
&.empty-header {
visibility: hidden;
}
}
.grid-park-name {
font-size: 13px;
color: #333;
margin-bottom: 8px;
text-align: left;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
}
.grid-number {
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
text-align: center;
height: 24px;
line-height: 24px;
color: #1f2937;
&:last-child {
margin-bottom: 0;
}
}
}
.high-risk-top { .high-risk-top {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -38,13 +38,30 @@
<Echart :options="outsourcingChartOption" width="100%" height="200px" /> <Echart :options="outsourcingChartOption" width="100%" height="200px" />
</div> </div>
<div class="region-distribution"> <div class="region-distribution">
<div class="distribution-title">供应商分布</div> <div class="distribution-title">供应商人数分布</div>
<div class="distribution-list"> <div class="grid-wrapper">
<div class="distribution-item" v-for="item in supplierDistribution" :key="item.supplier"> <!-- 第一列供应商名称 -->
<span class="dot" :style="{ backgroundColor: item.color }"></span> <div class="grid-column">
<span class="region-name">{{ item.supplier }}</span> <div class="grid-header empty-header"></div>
<span class="region-count">{{ item.count }}</span> <div class="grid-park-name" v-for="item in supplierDistribution" :key="'area-' + item.supplier">
<span class="region-percent">({{ item.percent }})</span> {{ item.supplier }}
</div>
</div>
<!-- 人数列 -->
<div class="grid-column">
<div class="grid-header">人数</div>
<div class="grid-number" v-for="item in supplierDistribution"
:key="'count-' + item.supplier">
{{ item.count }}
</div>
</div>
<!-- 占比列 -->
<div class="grid-column">
<div class="grid-header">占比</div>
<div class="grid-number" v-for="item in supplierDistribution"
:key="'percent-' + item.supplier">
{{ item.percent }}
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -66,27 +83,46 @@
</div> </div>
<div class="risk-distribution-table"> <div class="risk-distribution-table">
<div class="distribution-title">地点风险分布</div> <div class="distribution-title">地点风险分布</div>
<div class="table-wrapper"> <div class="grid-wrapper">
<table class="risk-table"> <!-- 第一列地点名称 -->
<thead> <div class="grid-column">
<tr> <div class="grid-header empty-header"></div>
<th>所在地点</th> <div class="grid-park-name" v-for="item in locationRiskDistribution" :key="'area-' + item.location">
<th></th> {{ item.location }}
<th>一般</th> </div>
<th>较大</th> </div>
<th>重大</th> <!-- 低列 -->
</tr> <div class="grid-column">
</thead> <div class="grid-header status-low"></div>
<tbody> <div class="grid-number status-low" v-for="item in locationRiskDistribution"
<tr v-for="item in locationRiskDistribution" :key="item.location"> :key="'low-' + item.location">
<td>{{ item.location }}</td> {{ item.low || '0' }}
<td>{{ item.low || '' }}</td> </div>
<td>{{ item.general }}</td> </div>
<td>{{ item.moderate }}</td> <!-- 一般列 -->
<td>{{ item.major }}</td> <div class="grid-column">
</tr> <div class="grid-header status-general">一般</div>
</tbody> <div class="grid-number status-general" v-for="item in locationRiskDistribution"
</table> :key="'general-' + item.location">
{{ item.general || '0' }}
</div>
</div>
<!-- 较大列 -->
<div class="grid-column">
<div class="grid-header status-moderate">较大</div>
<div class="grid-number status-moderate" v-for="item in locationRiskDistribution"
:key="'moderate-' + item.location">
{{ item.moderate || '0' }}
</div>
</div>
<!-- 重大列 -->
<div class="grid-column">
<div class="grid-header status-major">重大</div>
<div class="grid-number status-major" v-for="item in locationRiskDistribution"
:key="'major-' + item.location">
{{ item.major || '0' }}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -107,7 +143,10 @@
</div> </div>
<div class="rectification-status-grid"> <div class="rectification-status-grid">
<div class="distribution-title">所属公司整改状态</div> <div class="distribution-title">所属公司整改状态</div>
<div class="grid-wrapper"> <div v-if="companyRectificationStatus.length === 0" class="empty-data-tip">
暂无数据
</div>
<div v-else class="grid-wrapper">
<!-- 第一列公司名称 --> <!-- 第一列公司名称 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header empty-header"></div> <div class="grid-header empty-header"></div>
@@ -119,21 +158,21 @@
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-overdue">已逾期</div> <div class="grid-header status-overdue">已逾期</div>
<div class="grid-number status-overdue" v-for="item in companyRectificationStatus" :key="'overdue-' + item.company"> <div class="grid-number status-overdue" v-for="item in companyRectificationStatus" :key="'overdue-' + item.company">
{{ item.overdue }} {{ item.overdue ?? 0 }}
</div> </div>
</div> </div>
<!-- 处理中列 --> <!-- 处理中列 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-processing">处理中</div> <div class="grid-header status-processing">处理中</div>
<div class="grid-number status-processing" v-for="item in companyRectificationStatus" :key="'processing-' + item.company"> <div class="grid-number status-processing" v-for="item in companyRectificationStatus" :key="'processing-' + item.company">
{{ item.processing }} {{ item.processing ?? 0 }}
</div> </div>
</div> </div>
<!-- 已处理列 --> <!-- 已处理列 -->
<div class="grid-column"> <div class="grid-column">
<div class="grid-header status-processed">已处理</div> <div class="grid-header status-processed">已处理</div>
<div class="grid-number status-processed" v-for="item in companyRectificationStatus" :key="'processed-' + item.company"> <div class="grid-number status-processed" v-for="item in companyRectificationStatus" :key="'processed-' + item.company">
{{ item.processed }} {{ item.processed ?? 0 }}
</div> </div>
</div> </div>
</div> </div>
@@ -319,22 +358,22 @@ const route = useRoute()
// 应急预案:/yayl/table/view/1966394259751907330 // 应急预案:/yayl/table/view/1966394259751907330
// 安全培训:/pxks/table/view/1968225010550091777 // 安全培训:/pxks/table/view/1968225010550091777
const openOutsourcingManagement = () => { const openOutsourcingManagement = () => {
window.open('/person/table/view/1959187451673116674', '_blank') router.push('/person/table/view/1959187451673116674')
} }
const openRiskManagement = () => { const openRiskManagement = () => {
window.open('/fx/table/view/1978723750599790594', '_blank') router.push('/fx/table/view/1978723750599790594')
} }
const openHiddenDangerManagement = () => { const openHiddenDangerManagement = () => {
window.open('/fx/table/view/1963446160885366786', '_blank') router.push('/fx/table/view/1963446160885366786')
} }
const openHighRiskManagement = () => { const openHighRiskManagement = () => {
window.open('/low/table/view/1964253329070571521', '_blank') router.push('/low/table/view/1964253329070571521')
} }
const openEmergencyPlanManagement = () => { const openEmergencyPlanManagement = () => {
window.open('/yayl/table/view/1966394259751907330', '_blank') router.push('/yayl/table/view/1966394259751907330')
} }
const openTrainingManagement = () => { const openTrainingManagement = () => {
window.open('/pxks/table/view/1968225010550091777', '_blank') router.push('/pxks/table/view/1968225010550091777')
} }
// 园区名称 - 从路由参数获取 // 园区名称 - 从路由参数获取
const selectedPark = ref<string>('') const selectedPark = ref<string>('')
@@ -1051,8 +1090,11 @@ const riskChartOption = computed<EChartsOption>(() => {
// 隐患管理折线图配置 // 隐患管理折线图配置
const hiddenDangerChartOption = computed<EChartsOption>(() => { const hiddenDangerChartOption = computed<EChartsOption>(() => {
const dates = hiddenDangerTrend.value.map(item => item.date) const dates = hiddenDangerTrend.value.map(item => item.date)
const generalData = hiddenDangerTrend.value.map(item => item.general) const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0)
const majorData = hiddenDangerTrend.value.map(item => item.major) const majorData = hiddenDangerTrend.value.map(item => item.major ?? 0)
// 判断是否为空数据
const isEmpty = dates.length === 0 || (generalData.every(v => v === 0) && majorData.every(v => v === 0))
return { return {
tooltip: { trigger: 'axis' }, tooltip: { trigger: 'axis' },
@@ -1060,14 +1102,41 @@ const hiddenDangerChartOption = computed<EChartsOption>(() => {
data: ['一般隐患', '重大隐患'], data: ['一般隐患', '重大隐患'],
top: 10 top: 10
}, },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, grid: { left: '3%', right: '4%', bottom: '3%', top: '12%', containLabel: true },
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: dates data: dates,
show: !isEmpty
}, },
yAxis: { type: 'value', max: 45 }, yAxis: {
series: [ type: 'value',
max: 45,
show: !isEmpty
},
graphic: isEmpty ? [
{
type: 'group',
left: 'center',
top: 'center',
children: [
{
type: 'text',
z: 100,
left: 'center',
top: 'center',
style: {
text: '暂无数据',
fontSize: 16,
fontWeight: 'normal',
fill: '#9ca3af',
textAlign: 'center'
}
}
]
}
] : [],
series: isEmpty ? [] : [
{ {
name: '一般隐患', name: '一般隐患',
type: 'line', type: 'line',
@@ -1466,6 +1535,14 @@ onMounted(() => {
font-weight: bold; font-weight: bold;
color: #333; color: #333;
margin-bottom: 10px; margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
span {
font-size: 14px;
font-weight: 600;
color: #374151;
}
} }
.distribution-list { .distribution-list {
@@ -1502,11 +1579,104 @@ onMounted(() => {
color: #999; color: #999;
} }
.table-wrapper { // 风险管理网格样式(与隐患管理一致)
overflow-x: auto; .risk-distribution-table {
.grid-wrapper {
display: flex;
gap: 0;
justify-content: flex-start;
}
.grid-column {
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
&:first-child {
align-items: flex-start;
margin-right: 20px;
flex: 0 0 auto;
min-width: 80px;
}
&:not(:first-child) {
flex: 1;
min-width: 60px;
}
}
.grid-header {
font-size: 14px;
font-weight: bold;
margin-bottom: 12px;
height: 20px;
line-height: 20px;
&.empty-header {
visibility: hidden;
}
&.status-low {
color: #117cee;
}
&.status-general {
color: #fbde28;
}
&.status-moderate {
color: #ed740c;
}
&.status-major {
color: #df2a3f;
}
}
.grid-park-name {
font-size: 13px;
color: #333;
margin-bottom: 8px;
text-align: left;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
}
.grid-number {
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
text-align: center;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
&.status-low {
color: #117cee;
}
&.status-general {
color: #fbde28;
}
&.status-moderate {
color: #ed740c;
}
&.status-major {
color: #df2a3f;
}
}
} }
.risk-table,
.status-table { .status-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
@@ -1535,6 +1705,13 @@ onMounted(() => {
// 九宫格样式 // 九宫格样式
// 九宫格样式 // 九宫格样式
.rectification-status-grid { .rectification-status-grid {
.empty-data-tip {
text-align: center;
padding: 40px 0;
color: #9ca3af;
font-size: 14px;
}
.grid-wrapper { .grid-wrapper {
display: flex; display: flex;
gap: 0; gap: 0;
@@ -1623,6 +1800,74 @@ onMounted(() => {
} }
} }
// 外协管理网格样式(与隐患管理一致)
.region-distribution {
.grid-wrapper {
display: flex;
gap: 0;
justify-content: flex-start;
}
.grid-column {
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
&:first-child {
align-items: flex-start;
margin-right: 20px;
flex: 0 0 auto;
min-width: 80px;
}
&:not(:first-child) {
flex: 1;
min-width: 60px;
}
}
.grid-header {
font-size: 14px;
font-weight: bold;
margin-bottom: 12px;
height: 20px;
line-height: 20px;
color: #374151;
&.empty-header {
visibility: hidden;
}
}
.grid-park-name {
font-size: 13px;
color: #333;
margin-bottom: 8px;
text-align: left;
height: 24px;
line-height: 24px;
&:last-child {
margin-bottom: 0;
}
}
.grid-number {
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
text-align: center;
height: 24px;
line-height: 24px;
color: #1f2937;
&:last-child {
margin-bottom: 0;
}
}
}
.high-risk-top { .high-risk-top {
display: flex; display: flex;
align-items: center; align-items: center;