全景画像入口页面

This commit is contained in:
qweasdzxclm 2026-01-19 11:07:43 +08:00
parent 29c8f7f562
commit bb95119354
2 changed files with 533 additions and 0 deletions

View File

@ -184,6 +184,26 @@ const remainingRouter: AppRouteRecordRaw[] = [
noTagsView: true
}
},
{
path: '/dashentry',
component: Layout,
name: 'DashEntryL',
meta: {
hidden: true
},
children: [
{
path: '',
component: () => import('@/views/DashEntry/DashEntry.vue'),
name: 'DashEntry',
meta: {
hidden: true,
title: 'DashEntry',
noTagsView: true
}
}
]
},
{
path: '/login',
component: () => import('@/views/Login/Login.vue'),

View File

@ -0,0 +1,513 @@
<template>
<div class="dash-entry-container">
<!-- 顶部四个数据卡片 -->
<div class="stats-cards">
<div v-for="(card, index) in statsCards" :key="index" class="stat-card">
<div class="stat-card-icon" :class="`icon-${card.type}`">
<Icon :icon="card.icon" :size="20" />
</div>
<div class="stat-card-content">
<div class="stat-card-title">{{ card.title }}</div>
<div class="stat-card-value">{{ card.value }}</div>
<div class="stat-card-subtitle">
{{ card.subtitle }}
<span class="trend-icon" :class="card.trend === 'up' ? 'trend-up' : 'trend-down'">{{
card.trend === 'up' ? '↑' : '↓'
}}</span>
</div>
</div>
</div>
</div>
<!-- 中间图表区域 -->
<div class="charts-section">
<!-- 左侧风险等级分布环形图 -->
<div class="chart-card">
<div class="chart-title">风险等级分布</div>
<div class="chart-content">
<EChart :options="riskDistributionOptions" :width="'100%'" :height="'300px'" />
</div>
</div>
<!-- 右侧风险趋势图折线图 -->
<div class="chart-card">
<div class="chart-title">风险趋势图</div>
<div class="chart-content">
<EChart :options="riskTrendOptions" :height="'300px'" />
</div>
</div>
</div>
<!-- 底部表格 -->
<div class="table-section">
<div class="table-title">重点关注对象列表</div>
<el-table :data="paginatedResults" style="width: 100%" stripe>
<el-table-column prop="name" label="姓名" width="130" class-name="name-column">
<template #default="{ row }">
<span v-if="row.isNew" class="new-tag">新增</span>
{{ row.name }}
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" width="80" />
<el-table-column prop="age" label="年龄" width="80" />
<el-table-column prop="riskLevel" label="风险等级" width="120">
<template #default="{ row }">
<span :class="`risk-level risk-${row.riskLevelType}`">
{{ row.riskLevel }}
</span>
</template>
</el-table-column>
<el-table-column prop="supervisionArea" label="监区" width="120" />
<el-table-column prop="psychologicalRiskLevel" label="心理风险等级" width="150" />
<el-table-column label="操作" width="120">
<template #default="{ row }">
<el-link type="primary" @click="handleView(row)">全景画像</el-link>
</template>
</el-table-column>
</el-table>
<div class="table-pagination">
<span class="total-count">{{ tableData.total }}</span>
<el-pagination
v-model:current-page="tableData.current"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="tableData.total"
layout="sizes, prev, pager, next"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { EChartsOption } from 'echarts'
// @ts-ignore
import EChart from '@/components/Echart/src/Echart.vue'
import { Icon } from '@/components/Icon'
import { useRouter } from 'vue-router'
defineOptions({ name: 'DashEntry' })
const router = useRouter()
//
const statsCards = ref([
{
title: '全部人员',
value: '59人',
subtitle: '本月45人 +15',
trend: 'up',
type: 'all',
icon: 'ep:user'
},
{
title: '高危人员',
value: '12人',
subtitle: '本月3人 -3',
trend: 'down',
type: 'high',
icon: 'ep:warning-filled'
},
{
title: '预警人员',
value: '23人',
subtitle: '本月4人 +2',
trend: 'up',
type: 'warning',
icon: 'ep:bell'
},
{
title: '普通人员',
value: '32人',
subtitle: '本月5人 +1',
trend: 'up',
type: 'normal',
icon: 'ep:user-filled'
}
])
//
const riskDistributionOptions = computed<EChartsOption>(() => ({
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
show: true,
bottom: 0,
left: 'center',
itemGap: 20,
icon: 'circle',
textStyle: {
fontSize: 12
},
data: ['普通 (80%)', '预警 (15%)', '高危 (5%)']
},
series: [
{
name: '风险等级分布',
type: 'pie',
radius: ['40%', '70%'],
center: ['50%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: '{b}\n{d}%'
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: [
{ value: 978, name: '普通 (80%)', itemStyle: { color: '#5470c6' } },
{ value: 189, name: '预警 (15%)', itemStyle: { color: '#fac858' } },
{ value: 67, name: '高危 (5%)', itemStyle: { color: '#ee6666' } }
]
}
]
}))
// 线
const riskTrendOptions = computed<EChartsOption>(() => ({
tooltip: {
trigger: 'axis'
},
legend: {
data: ['高危', '预警', '普通'],
bottom: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '15%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['2024-10', '2024-11', '2024-12', '2025-01', '2025-02', '2025-03', '2025-04']
},
yAxis: {
type: 'value',
min: 0,
max: 300,
interval: 50
},
series: [
{
name: '高危',
type: 'line',
data: [50, 52, 48, 51, 49, 50, 48],
itemStyle: { color: '#ee6666' },
lineStyle: { color: '#ee6666' },
symbol: 'circle',
symbolSize: 6
},
{
name: '预警',
type: 'line',
data: [150, 180, 170, 190, 185, 175, 180],
itemStyle: { color: '#fac858' },
lineStyle: { color: '#fac858', type: 'dashed' },
symbol: 'circle',
symbolSize: 6
},
{
name: '普通',
type: 'line',
data: [250, 280, 270, 290, 285, 275, 280],
itemStyle: { color: '#666' },
lineStyle: { color: '#666' },
symbol: 'circle',
symbolSize: 6
}
]
}))
//
const tableData = ref({
current: 1,
total: 3,
results: [
{
name: '王建国',
isNew: true,
gender: '男',
age: 34,
riskLevel: '高危',
riskLevelType: 'high',
supervisionArea: '第一监区',
psychologicalRiskLevel: '一级风险'
},
{
name: '李秀英',
isNew: true,
gender: '女',
age: 29,
riskLevel: '预警',
riskLevelType: 'warning',
supervisionArea: '第二监区',
psychologicalRiskLevel: '二级风险'
},
{
name: '张伟',
isNew: false,
gender: '男',
age: 41,
riskLevel: '普通',
riskLevelType: 'normal',
supervisionArea: '第一监区',
psychologicalRiskLevel: '三级风险'
}
]
})
//
const pageSize = ref(10)
//
const paginatedResults = computed(() => {
const start = (tableData.value.current - 1) * pageSize.value
const end = start + pageSize.value
return tableData.value.results.slice(start, end)
})
//
const handleSizeChange = (val: number) => {
pageSize.value = val
tableData.value.current = 1 //
}
//
const handleCurrentChange = (val: number) => {
tableData.value.current = val
}
const handleView = (row: any) => {
router.push({
name: 'Dashboard',
query: {
id: row.id || row.name
}
})
}
</script>
<style scoped lang="scss">
.dash-entry-container {
padding: 20px;
background: #f5f5f5;
min-height: 100vh;
width: 100%;
box-sizing: border-box;
}
//
.stats-cards {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
margin-bottom: 20px;
width: 100%;
box-sizing: border-box;
}
.stat-card {
background: #ffffff;
border-radius: 8px;
padding: 10px 20px;
display: flex;
align-items: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.2s;
width: 100%;
box-sizing: border-box;
min-width: 0;
position: relative;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
}
.stat-card-icon {
position: absolute;
top: 10px;
right: 0;
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
font-size: 28px;
&.icon-all {
background: #e6f4ff;
color: #1890ff;
}
&.icon-high {
background: #fff1f0;
color: #ff4d4f;
}
&.icon-warning {
background: #fff7e6;
color: #faad14;
}
&.icon-normal {
background: #f6ffed;
color: #52c41a;
}
}
.stat-card-content {
flex: 1;
min-width: 0;
overflow: hidden;
}
.stat-card-title {
font-size: 9px;
color: #666;
margin-bottom: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.stat-card-value {
font-size: 10px;
font-weight: bold;
color: #333;
margin-bottom: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.stat-card-subtitle {
font-size: 8px;
color: #999;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.trend-icon {
margin-left: 4px;
&.trend-up {
color: #52c41a;
}
&.trend-down {
color: #ff4d4f;
}
}
}
//
.charts-section {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 20px;
}
.chart-card {
background: #ffffff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.chart-title {
font-size: 11px;
font-weight: bold;
color: #333;
margin-bottom: 16px;
}
.chart-content {
height: 250px;
}
//
.table-section {
background: #ffffff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.table-title {
font-size: 11px;
font-weight: bold;
color: #333;
margin-bottom: 16px;
}
:deep(.name-column) {
padding-left: 20px;
}
.new-tag {
display: inline-block;
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 0;
padding: 1px 3px;
background: #1890ff;
color: #ffffff;
font-size: 9px;
border-radius: 2px;
margin-right: 8px;
}
.risk-level {
padding: 4px 8px;
border-radius: 4px;
font-size: 9px;
&.risk-high {
color: #ff4d4f;
background: #fff1f0;
}
&.risk-warning {
color: #faad14;
background: #fff7e6;
}
&.risk-normal {
color: #666;
background: #f5f5f5;
}
}
.table-pagination {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 16px;
.total-count {
color: #666;
font-size: 14px;
}
}
</style>