首页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" />
</div>
<div class="region-distribution">
<div class="distribution-title">区域分布</div>
<div class="distribution-list">
<div class="distribution-item" v-for="item in outsourcingDistribution" :key="item.region">
<span class="dot" :style="{ backgroundColor: item.color }"></span>
<span class="region-name">{{ item.region }}</span>
<span class="region-count">{{ item.count }}</span>
<span class="region-percent">({{ item.percent }})</span>
<div class="distribution-title">区域人数分布</div>
<div class="grid-wrapper">
<!-- 第一列区域名称 -->
<div class="grid-column">
<div class="grid-header empty-header"></div>
<div class="grid-park-name" v-for="item in outsourcingDistribution" :key="'area-' + item.region">
{{ 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>
@@ -66,27 +83,46 @@
</div>
<div class="risk-distribution-table">
<div class="distribution-title">区域风险分布</div>
<div class="table-wrapper">
<table class="risk-table">
<thead>
<tr>
<th>区域</th>
<th></th>
<th>一般</th>
<th>较大</th>
<th>重大</th>
</tr>
</thead>
<tbody>
<tr v-for="item in areaRiskDistribution" :key="item.area">
<td>{{ item.area }}</td>
<td>{{ item.low || '0' }}</td>
<td>{{ item.general || '0' }}</td>
<td>{{ item.moderate || '0' }}</td>
<td>{{ item.major || '0' }}</td>
</tr>
</tbody>
</table>
<div class="grid-wrapper">
<!-- 第一列区域名称 -->
<div class="grid-column">
<div class="grid-header empty-header"></div>
<div class="grid-park-name" v-for="item in areaRiskDistribution" :key="'area-' + item.area">
{{ item.area }}
</div>
</div>
<!-- 低列 -->
<div class="grid-column">
<div class="grid-header status-low"></div>
<div class="grid-number status-low" v-for="item in areaRiskDistribution"
:key="'low-' + item.area">
{{ item.low || '0' }}
</div>
</div>
<!-- 一般列 -->
<div class="grid-column">
<div class="grid-header status-general">一般</div>
<div class="grid-number status-general" v-for="item in areaRiskDistribution"
: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>
@@ -107,7 +143,10 @@
</div>
<div class="rectification-status-grid">
<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-header empty-header"></div>
@@ -118,22 +157,25 @@
<!-- 已逾期列 -->
<div class="grid-column">
<div class="grid-header status-overdue">已逾期</div>
<div class="grid-number status-overdue" v-for="item in areaRectificationStatus" :key="'overdue-' + item.area">
{{ item.overdue }}
<div class="grid-number status-overdue" v-for="item in areaRectificationStatus"
:key="'overdue-' + item.area">
{{ item.overdue ?? 0 }}
</div>
</div>
<!-- 处理中列 -->
<div class="grid-column">
<div class="grid-header status-processing">处理中</div>
<div class="grid-number status-processing" v-for="item in areaRectificationStatus" :key="'processing-' + item.area">
{{ item.processing }}
<div class="grid-number status-processing" v-for="item in areaRectificationStatus"
:key="'processing-' + item.area">
{{ item.processing ?? 0 }}
</div>
</div>
<!-- 已处理列 -->
<div class="grid-column">
<div class="grid-header status-processed">已处理</div>
<div class="grid-number status-processed" v-for="item in areaRectificationStatus" :key="'processed-' + item.area">
{{ item.processed }}
<div class="grid-number status-processed" v-for="item in areaRectificationStatus"
:key="'processed-' + item.area">
{{ item.processed ?? 0 }}
</div>
</div>
</div>
@@ -336,22 +378,23 @@ const dateRange = ref(getInitialDateRange())
// 应急预案:/yayl/table/view/1966394259751907330
// 安全培训:/pxks/table/view/1968225010550091777
const openOutsourcingManagement = () => {
window.open('/person/table/view/1959187451673116674', '_blank')
// 不打开新标签页
router.push('/person/table/view/1959187451673116674')
}
const openRiskManagement = () => {
window.open('/fx/table/view/1978723750599790594', '_blank')
router.push('/fx/table/view/1978723750599790594')
}
const openHiddenDangerManagement = () => {
window.open('/fx/table/view/1963446160885366786', '_blank')
router.push('/fx/table/view/1963446160885366786')
}
const openHighRiskManagement = () => {
window.open('/low/table/view/1964253329070571521', '_blank')
router.push('/low/table/view/1964253329070571521')
}
const openEmergencyPlanManagement = () => {
window.open('/yayl/table/view/1966394259751907330', '_blank')
router.push('/yayl/table/view/1966394259751907330')
}
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 dates = hiddenDangerTrend.value.map(item => item.date)
const generalData = hiddenDangerTrend.value.map(item => item.general)
const majorData = hiddenDangerTrend.value.map(item => item.major)
const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0)
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的倍数
const maxValue = Math.max(
const maxValue = isEmpty ? 10 : Math.max(
...generalData,
...majorData,
10 // 最小值为10避免图表显示过小
@@ -646,18 +692,42 @@ const hiddenDangerChartOption = computed<EChartsOption>(() => {
xAxis: {
type: 'category',
boundaryGap: false,
data: dates.length > 0 ? dates : []
data: dates.length > 0 ? dates : [],
show: !isEmpty
},
yAxis: {
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: '一般隐患',
type: 'line',
smooth: true,
data: generalData.length > 0 ? generalData : [],
data: generalData,
itemStyle: { color: '#f59e0b' },
lineStyle: { color: '#f59e0b', width: 2 },
areaStyle: {
@@ -678,7 +748,7 @@ const hiddenDangerChartOption = computed<EChartsOption>(() => {
name: '重大隐患',
type: 'line',
smooth: true,
data: majorData.length > 0 ? majorData : [],
data: majorData,
itemStyle: { color: '#ef4444' },
lineStyle: { color: '#ef4444', width: 2 },
areaStyle: {
@@ -1540,15 +1610,15 @@ onMounted(async () => {
color: white;
user-select: none;
font-weight: 600;
span {
margin-left: 8px;
font-size: 18px;
color: #6b7280;
}
gap: 5px;
&:hover {
background: #e5e7eb;
border-color: #d1d5db;
background: #2563eb;
}
span {
font-size: 18px;
line-height: 1;
}
&:active {
@@ -1616,6 +1686,7 @@ onMounted(async () => {
}
@media (max-width: 1200px) {
.high-risk-top,
.emergency-plan-top {
gap: 10px;
@@ -1634,6 +1705,7 @@ onMounted(async () => {
}
@media (max-width: 768px) {
.high-risk-top,
.emergency-plan-top {
flex-direction: column;
@@ -1825,6 +1897,14 @@ onMounted(async () => {
font-weight: 600;
color: #374151;
margin-bottom: 12px;
display: flex;
align-items: center;
justify-content: space-between;
span {
font-size: 14px;
font-weight: 600;
color: #374151;
}
}
.distribution-list {
@@ -1868,6 +1948,13 @@ onMounted(async () => {
// 网格样式
.rectification-status-grid {
.empty-data-tip {
text-align: center;
padding: 40px 0;
color: #9ca3af;
font-size: 14px;
}
.grid-wrapper {
display: flex;
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%;
border-collapse: collapse;
font-size: 13px;
thead {
background-color: #f9fafb;
// 外协管理网格样式(与隐患管理一致)
.region-distribution {
.grid-wrapper {
display: flex;
gap: 0;
justify-content: flex-start;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #e5e7eb;
.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;
}
}
th {
.grid-header {
font-size: 14px;
font-weight: bold;
color: #333;
margin-bottom: 12px;
height: 20px;
line-height: 20px;
color: #374151;
&.empty-header {
visibility: hidden;
}
}
td {
color: #666;
.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;
}
}
}
@@ -2060,12 +2284,10 @@ onMounted(async () => {
left: 0;
bottom: 0;
right: 0;
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.3) 50%,
transparent 100%
);
background: linear-gradient(90deg,
transparent 0%,
rgba(255, 255, 255, 0.3) 50%,
transparent 100%);
animation: shimmer 2s infinite;
}
}
@@ -2084,6 +2306,7 @@ onMounted(async () => {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}

View File

@@ -41,16 +41,33 @@
<Echart :options="outsourcingChartOption" width="100%" height="200px" />
</div>
<div class="region-distribution">
<div class="distribution-title">园区分布</div>
<div class="distribution-list">
<div class="distribution-item" v-for="item in outsourcingDistribution" :key="item.region">
<span class="dot" :style="{ backgroundColor: item.color }"></span>
<span class="region-name">{{ item.region }}</span>
<span class="region-count">{{ item.count }}</span>
<span class="region-percent">({{ item.percent }})</span>
</div>
<div class="distribution-title">园区人数分布</div>
<div class="grid-wrapper">
<!-- 第一列园区名称 -->
<div class="grid-column">
<div class="grid-header empty-header"></div>
<div class="grid-park-name" v-for="item in outsourcingDistribution" :key="'area-' + item.region">
{{ 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>
@@ -69,28 +86,47 @@
</div>
<div class="risk-distribution-table">
<div class="distribution-title">园区风险分布</div>
<div class="table-wrapper">
<table class="risk-table">
<thead>
<tr>
<th>园区</th>
<th></th>
<th>一般</th>
<th>较大</th>
<th>重大</th>
</tr>
</thead>
<tbody>
<tr v-for="item in parkRiskDistribution" :key="item.park">
<td>{{ item.park }}</td>
<td>{{ item.low || '' }}</td>
<td>{{ item.general }}</td>
<td>{{ item.moderate }}</td>
<td>{{ item.major }}</td>
</tr>
</tbody>
</table>
</div>
<div class="grid-wrapper">
<!-- 第一列园区名称 -->
<div class="grid-column">
<div class="grid-header empty-header"></div>
<div class="grid-park-name" v-for="item in parkRiskDistribution" :key="'area-' + item.park">
{{ item.park }}
</div>
</div>
<!-- 低列 -->
<div class="grid-column">
<div class="grid-header status-low"></div>
<div class="grid-number status-low" v-for="item in parkRiskDistribution"
:key="'low-' + item.park">
{{ item.low || '0' }}
</div>
</div>
<!-- 一般列 -->
<div class="grid-column">
<div class="grid-header status-general">一般</div>
<div class="grid-number status-general" v-for="item in parkRiskDistribution"
: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>
@@ -110,7 +146,10 @@
</div>
<div class="rectification-status-grid">
<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-header empty-header"></div>
@@ -122,21 +161,21 @@
<div class="grid-column">
<div class="grid-header status-overdue">已逾期</div>
<div class="grid-number status-overdue" v-for="item in parkRectificationStatus" :key="'overdue-' + item.park">
{{ item.overdue }}
{{ item.overdue ?? 0 }}
</div>
</div>
<!-- 处理中列 -->
<div class="grid-column">
<div class="grid-header status-processing">处理中</div>
<div class="grid-number status-processing" v-for="item in parkRectificationStatus" :key="'processing-' + item.park">
{{ item.processing }}
{{ item.processing ?? 0 }}
</div>
</div>
<!-- 已处理列 -->
<div class="grid-column">
<div class="grid-header status-processed">已处理</div>
<div class="grid-number status-processed" v-for="item in parkRectificationStatus" :key="'processed-' + item.park">
{{ item.processed }}
{{ item.processed ?? 0 }}
</div>
</div>
</div>
@@ -329,22 +368,22 @@ const parkOption = ref<ParkItem[]>([])
// 应急预案:/yayl/table/view/1966394259751907330
// 安全培训:/pxks/table/view/1968225010550091777
const openOutsourcingManagement = () => {
window.open('/person/table/view/1959187451673116674', '_blank')
router.push('/person/table/view/1959187451673116674')
}
const openRiskManagement = () => {
window.open('/fx/table/view/1978723750599790594', '_blank')
router.push('/fx/table/view/1978723750599790594')
}
const openHiddenDangerManagement = () => {
window.open('/fx/table/view/1963446160885366786', '_blank')
router.push('/fx/table/view/1963446160885366786')
}
const openHighRiskManagement = () => {
window.open('/low/table/view/1964253329070571521', '_blank')
router.push('/low/table/view/1964253329070571521')
}
const openEmergencyPlanManagement = () => {
window.open('/yayl/table/view/1966394259751907330', '_blank')
router.push('/yayl/table/view/1966394259751907330')
}
const openTrainingManagement = () => {
window.open('/pxks/table/view/1968225010550091777', '_blank')
router.push('/pxks/table/view/1968225010550091777')
}
// 时间选择相关 - 默认当前月起止,如果路由中有日期范围参数则使用
const getCurrentMonthRange = () => {
@@ -1130,8 +1169,11 @@ const riskChartOption = computed<EChartsOption>(() => {
// 隐患管理折线图配置
const hiddenDangerChartOption = computed<EChartsOption>(() => {
const dates = hiddenDangerTrend.value.map(item => item.date)
const generalData = hiddenDangerTrend.value.map(item => item.general)
const majorData = hiddenDangerTrend.value.map(item => item.major)
const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0)
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 {
tooltip: { trigger: 'axis' },
@@ -1139,14 +1181,40 @@ const hiddenDangerChartOption = computed<EChartsOption>(() => {
data: ['一般隐患', '重大隐患'],
top: 10
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
grid: { left: '3%', right: '4%', bottom: '3%', top: '12%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: dates
data: dates,
show: !isEmpty
},
yAxis: { type: 'value' },
series: [
yAxis: {
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: '一般隐患',
type: 'line',
@@ -1559,6 +1627,14 @@ onMounted(() => {
font-weight: bold;
color: #333;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
span {
font-size: 14px;
font-weight: 600;
color: #374151;
}
}
.distribution-list {
@@ -1595,11 +1671,104 @@ onMounted(() => {
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 {
width: 100%;
border-collapse: collapse;
@@ -1616,7 +1785,7 @@ onMounted(() => {
}
th {
font-weight: bold;
font-weight: bold;
color: #333;
}
@@ -1627,6 +1796,13 @@ onMounted(() => {
// 九宫格样式
.rectification-status-grid {
.empty-data-tip {
text-align: center;
padding: 40px 0;
color: #9ca3af;
font-size: 14px;
}
.grid-wrapper {
display: flex;
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 {
display: flex;
align-items: center;

View File

@@ -38,16 +38,33 @@
<Echart :options="outsourcingChartOption" width="100%" height="200px" />
</div>
<div class="region-distribution">
<div class="distribution-title">供应商分布</div>
<div class="distribution-list">
<div class="distribution-item" v-for="item in supplierDistribution" :key="item.supplier">
<span class="dot" :style="{ backgroundColor: item.color }"></span>
<span class="region-name">{{ item.supplier }}</span>
<span class="region-count">{{ item.count }}</span>
<span class="region-percent">({{ item.percent }})</span>
</div>
</div>
<div class="distribution-title">供应商人数分布</div>
<div class="grid-wrapper">
<!-- 第一列供应商名称 -->
<div class="grid-column">
<div class="grid-header empty-header"></div>
<div class="grid-park-name" v-for="item in supplierDistribution" :key="'area-' + item.supplier">
{{ 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>
@@ -66,28 +83,47 @@
</div>
<div class="risk-distribution-table">
<div class="distribution-title">地点风险分布</div>
<div class="table-wrapper">
<table class="risk-table">
<thead>
<tr>
<th>所在地点</th>
<th></th>
<th>一般</th>
<th>较大</th>
<th>重大</th>
</tr>
</thead>
<tbody>
<tr v-for="item in locationRiskDistribution" :key="item.location">
<td>{{ item.location }}</td>
<td>{{ item.low || '' }}</td>
<td>{{ item.general }}</td>
<td>{{ item.moderate }}</td>
<td>{{ item.major }}</td>
</tr>
</tbody>
</table>
</div>
<div class="grid-wrapper">
<!-- 第一列地点名称 -->
<div class="grid-column">
<div class="grid-header empty-header"></div>
<div class="grid-park-name" v-for="item in locationRiskDistribution" :key="'area-' + item.location">
{{ item.location }}
</div>
</div>
<!-- 低列 -->
<div class="grid-column">
<div class="grid-header status-low"></div>
<div class="grid-number status-low" v-for="item in locationRiskDistribution"
:key="'low-' + item.location">
{{ item.low || '0' }}
</div>
</div>
<!-- 一般列 -->
<div class="grid-column">
<div class="grid-header status-general">一般</div>
<div class="grid-number status-general" v-for="item in locationRiskDistribution"
: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>
@@ -107,7 +143,10 @@
</div>
<div class="rectification-status-grid">
<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-header empty-header"></div>
@@ -119,21 +158,21 @@
<div class="grid-column">
<div class="grid-header status-overdue">已逾期</div>
<div class="grid-number status-overdue" v-for="item in companyRectificationStatus" :key="'overdue-' + item.company">
{{ item.overdue }}
{{ item.overdue ?? 0 }}
</div>
</div>
<!-- 处理中列 -->
<div class="grid-column">
<div class="grid-header status-processing">处理中</div>
<div class="grid-number status-processing" v-for="item in companyRectificationStatus" :key="'processing-' + item.company">
{{ item.processing }}
{{ item.processing ?? 0 }}
</div>
</div>
<!-- 已处理列 -->
<div class="grid-column">
<div class="grid-header status-processed">已处理</div>
<div class="grid-number status-processed" v-for="item in companyRectificationStatus" :key="'processed-' + item.company">
{{ item.processed }}
{{ item.processed ?? 0 }}
</div>
</div>
</div>
@@ -319,22 +358,22 @@ const route = useRoute()
// 应急预案:/yayl/table/view/1966394259751907330
// 安全培训:/pxks/table/view/1968225010550091777
const openOutsourcingManagement = () => {
window.open('/person/table/view/1959187451673116674', '_blank')
router.push('/person/table/view/1959187451673116674')
}
const openRiskManagement = () => {
window.open('/fx/table/view/1978723750599790594', '_blank')
router.push('/fx/table/view/1978723750599790594')
}
const openHiddenDangerManagement = () => {
window.open('/fx/table/view/1963446160885366786', '_blank')
router.push('/fx/table/view/1963446160885366786')
}
const openHighRiskManagement = () => {
window.open('/low/table/view/1964253329070571521', '_blank')
router.push('/low/table/view/1964253329070571521')
}
const openEmergencyPlanManagement = () => {
window.open('/yayl/table/view/1966394259751907330', '_blank')
router.push('/yayl/table/view/1966394259751907330')
}
const openTrainingManagement = () => {
window.open('/pxks/table/view/1968225010550091777', '_blank')
router.push('/pxks/table/view/1968225010550091777')
}
// 园区名称 - 从路由参数获取
const selectedPark = ref<string>('')
@@ -1051,8 +1090,11 @@ const riskChartOption = computed<EChartsOption>(() => {
// 隐患管理折线图配置
const hiddenDangerChartOption = computed<EChartsOption>(() => {
const dates = hiddenDangerTrend.value.map(item => item.date)
const generalData = hiddenDangerTrend.value.map(item => item.general)
const majorData = hiddenDangerTrend.value.map(item => item.major)
const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0)
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 {
tooltip: { trigger: 'axis' },
@@ -1060,14 +1102,41 @@ const hiddenDangerChartOption = computed<EChartsOption>(() => {
data: ['一般隐患', '重大隐患'],
top: 10
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
grid: { left: '3%', right: '4%', bottom: '3%', top: '12%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: dates
data: dates,
show: !isEmpty
},
yAxis: { type: 'value', max: 45 },
series: [
yAxis: {
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: '一般隐患',
type: 'line',
@@ -1466,6 +1535,14 @@ onMounted(() => {
font-weight: bold;
color: #333;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
span {
font-size: 14px;
font-weight: 600;
color: #374151;
}
}
.distribution-list {
@@ -1502,11 +1579,104 @@ onMounted(() => {
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 {
width: 100%;
border-collapse: collapse;
@@ -1535,6 +1705,13 @@ onMounted(() => {
// 九宫格样式
// 九宫格样式
.rectification-status-grid {
.empty-data-tip {
text-align: center;
padding: 40px 0;
color: #9ca3af;
font-size: 14px;
}
.grid-wrapper {
display: flex;
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 {
display: flex;
align-items: center;