| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- <template>
- <div class="app-container">
- <!-- 搜索区域 -->
- <el-form :model="queryParams" ref="queryRef" :inline="true" class="search-form">
- <el-form-item label="管网名称">
- <el-input v-model="queryParams.name" placeholder="请输入" clearable style="width: 160px" />
- </el-form-item>
- <el-form-item label="管网类型">
- <el-select v-model="queryParams.networkType" placeholder="请选择" clearable style="width: 160px">
- <el-option v-for="item in networkTypeOptions" :key="item" :label="item" :value="item" />
- </el-select>
- </el-form-item>
- <el-form-item label="所属区域">
- <el-input v-model="queryParams.area" placeholder="请输入" clearable style="width: 160px" />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="handleQuery">搜索</el-button>
- <el-button @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
- <!-- 统计概览卡片 -->
- <div class="stat-cards">
- <el-card class="stat-card stat-blue" shadow="hover">
- <div class="stat-card-inner">
- <div class="stat-icon"><el-icon :size="32"><DataLine /></el-icon></div>
- <div class="stat-info">
- <div class="stat-value">{{ stats.total }}</div>
- <div class="stat-label">总管网数</div>
- </div>
- </div>
- </el-card>
- <el-card class="stat-card stat-red" shadow="hover">
- <div class="stat-card-inner">
- <div class="stat-icon"><el-icon :size="32"><Warning /></el-icon></div>
- <div class="stat-info">
- <div class="stat-value">{{ stats.withAlarm }}</div>
- <div class="stat-label">有报警管网</div>
- </div>
- </div>
- </el-card>
- <el-card class="stat-card stat-orange" shadow="hover">
- <div class="stat-card-inner">
- <div class="stat-icon"><el-icon :size="32"><WarningFilled /></el-icon></div>
- <div class="stat-info">
- <div class="stat-value">{{ stats.totalAlarms }}</div>
- <div class="stat-label">总报警数</div>
- </div>
- </div>
- </el-card>
- <el-card class="stat-card stat-green" shadow="hover">
- <div class="stat-card-inner">
- <div class="stat-icon"><el-icon :size="32"><CircleCheck /></el-icon></div>
- <div class="stat-info">
- <div class="stat-value">{{ stats.noAlarm }}</div>
- <div class="stat-label">无报警管网</div>
- </div>
- </div>
- </el-card>
- </div>
- <!-- 数据表格 -->
- <el-table :data="tableData" border style="width: 100%" v-loading="loading">
- <el-table-column label="序号" type="index" width="60" align="center" :index="(i) => (pageNum - 1) * pageSize + i + 1" />
- <el-table-column label="管网名称" prop="name" min-width="180" />
- <el-table-column label="所属区域" prop="area" min-width="120" />
- <el-table-column label="管网类型" prop="networkType" min-width="100" align="center">
- <template #default="{ row }">
- <el-tag :type="networkTypeTagType(row.networkType)" effect="light">{{ row.networkType }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="关联设备" prop="equipmentId" min-width="100" align="center">
- <template #default="{ row }">
- <span v-if="row.equipmentId">已关联</span>
- <span v-else style="color:#909399">未关联</span>
- </template>
- </el-table-column>
- <el-table-column label="报警次数" min-width="100" align="center">
- <template #default="{ row }">
- <span :class="row._alarmCount > 0 ? 'alarm-has' : ''">{{ row._alarmCount ?? '-' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" prop="createTime" min-width="160" align="center" />
- <el-table-column label="操作" width="100" align="center" fixed="right">
- <template #default="{ row }">
- <el-button link type="primary" @click="handleDetail(row)">查看详情</el-button>
- </template>
- </el-table-column>
- </el-table>
- <!-- 分页 -->
- <div class="pagination-wrap">
- <el-pagination
- v-model:current-page="pageNum"
- v-model:page-size="pageSize"
- :page-sizes="[10, 20, 50]"
- :total="total"
- layout="total, sizes, prev, pager, next, jumper"
- background
- @size-change="loadData"
- @current-change="loadData"
- />
- </div>
- <!-- 详情弹窗 -->
- <el-drawer v-model="detailVisible" title="管网综合风险详情" size="800px" destroy-on-close class="detail-drawer" direction="rtl">
- <template v-if="currentRow">
- <el-tabs v-model="detailTab">
- <el-tab-pane label="基本信息" name="basic">
- <el-descriptions :column="2" border>
- <el-descriptions-item label="管网名称">{{ currentRow.name }}</el-descriptions-item>
- <el-descriptions-item label="所属区域">{{ currentRow.area }}</el-descriptions-item>
- <el-descriptions-item label="管网类型">
- <el-tag :type="networkTypeTagType(currentRow.networkType)" effect="light">{{ currentRow.networkType }}</el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="关联设备">{{ currentRow.equipmentId ? '已关联 (ID: ' + currentRow.equipmentId + ')' : '未关联' }}</el-descriptions-item>
- <el-descriptions-item label="坐标信息" :span="2">{{ formatPoints(currentRow.points) }}</el-descriptions-item>
- <el-descriptions-item label="创建时间">{{ currentRow.createTime }}</el-descriptions-item>
- <el-descriptions-item label="更新时间">{{ currentRow.updateTime }}</el-descriptions-item>
- </el-descriptions>
- </el-tab-pane>
- <el-tab-pane label="报警统计" name="alarm">
- <div v-if="currentRow.equipmentId" v-loading="alarmLoading">
- <div style="margin-bottom:16px">
- <el-tag :type="currentRow._alarmCount > 0 ? 'danger' : 'success'" size="large">
- 报警总数:{{ currentRow._alarmCount ?? 0 }}
- </el-tag>
- </div>
- <el-table :data="alarmList" border size="small" v-if="alarmList.length > 0">
- <el-table-column prop="alarmTime" label="报警时间" min-width="160" />
- <el-table-column prop="alarmType" label="报警类型" min-width="100" />
- <el-table-column prop="alarmContent" label="报警内容" min-width="200" />
- <el-table-column prop="status" label="状态" min-width="80" align="center">
- <template #default="{ row }">
- <el-tag :type="row.status === 0 ? 'warning' : row.status === 1 ? 'primary' : 'success'" size="small">
- {{ row.status === 0 ? '未处理' : row.status === 1 ? '处理中' : '已处理' }}
- </el-tag>
- </template>
- </el-table-column>
- </el-table>
- <el-empty v-else description="暂无报警数据" :image-size="60" />
- </div>
- <el-empty v-else description="该管网未关联设备,无报警数据" :image-size="60" />
- </el-tab-pane>
- </el-tabs>
- </template>
- <template #footer>
- <el-button @click="detailVisible = false">关 闭</el-button>
- </template>
- </el-drawer>
- </div>
- </template>
- <script setup name="Zhfxtjfx">
- import { ref, computed, onMounted } from 'vue'
- import { useRouter } from 'vue-router'
- import { DataLine, Warning, WarningFilled, CircleCheck } from '@element-plus/icons-vue'
- import { getPipeNetworkPage, getAlarmDataPage } from '@/api/drainage'
- const router = useRouter()
- // ==================== 下拉选项 ====================
- const networkTypeOptions = ['管线', '管点', '排口']
- // ==================== 搜索参数 ====================
- const queryParams = ref({ name: '', networkType: '管线', area: '' })
- const queryRef = ref(null)
- // ==================== 分页与数据 ====================
- const pageNum = ref(1)
- const pageSize = ref(10)
- const total = ref(0)
- const tableData = ref([])
- const loading = ref(false)
- const handleQuery = () => {
- pageNum.value = 1
- loadData()
- }
- const resetQuery = () => {
- queryParams.value = { name: '', networkType: '管线', area: '' }
- pageNum.value = 1
- loadData()
- }
- // ==================== 加载数据 ====================
- const loadData = async () => {
- loading.value = true
- try {
- const params = {}
- if (queryParams.value.name) params.name = queryParams.value.name
- if (queryParams.value.networkType) params.networkType = queryParams.value.networkType
- if (queryParams.value.area) params.area = queryParams.value.area
- const res = await getPipeNetworkPage(pageNum.value, pageSize.value, params)
- const pageData = res.code !== undefined ? res.data : res
- const rows = pageData.records || pageData.rows || []
- const totalCount = pageData.total ?? 0
- total.value = totalCount
- // 为每条管网查询报警数量
- const withAlarms = await Promise.all(
- rows.map(async (item) => {
- let alarmCount = 0
- if (item.equipmentId) {
- try {
- const alarmRes = await getAlarmDataPage(1, 1, { equipmentId: item.equipmentId, equipmentType: 'drainage' })
- const alarmPageData = alarmRes.code !== undefined ? alarmRes.data : alarmRes
- alarmCount = alarmPageData.total ?? 0
- } catch (e) { /* ignore */ }
- }
- return { ...item, _alarmCount: alarmCount }
- })
- )
- tableData.value = withAlarms
- } catch (e) {
- console.error('加载管网数据失败', e)
- tableData.value = []
- } finally {
- loading.value = false
- }
- }
- // ==================== 统计 ====================
- const stats = computed(() => {
- const list = tableData.value
- const withAlarm = list.filter(i => i._alarmCount > 0).length
- const totalAlarms = list.reduce((sum, i) => sum + (i._alarmCount || 0), 0)
- return {
- total: total.value,
- withAlarm,
- totalAlarms,
- noAlarm: list.length - withAlarm
- }
- })
- // ==================== 工具函数 ====================
- const networkTypeTagType = (type) => {
- const map = { '管线': '', '管点': 'warning', '排口': 'success' }
- return map[type] || ''
- }
- const formatPoints = (points) => {
- if (!points) return '暂无坐标'
- try {
- const parsed = typeof points === 'string' ? JSON.parse(points) : points
- if (Array.isArray(parsed)) {
- return parsed.map(p => `${p.lng || p[0]}, ${p.lat || p[1]}`).join(' → ')
- }
- return String(points)
- } catch {
- return String(points)
- }
- }
- // ==================== 详情弹窗 ====================
- const detailVisible = ref(false)
- const currentRow = ref(null)
- const detailTab = ref('basic')
- const alarmLoading = ref(false)
- const alarmList = ref([])
- const handleDetail = async (row) => {
- currentRow.value = row
- detailTab.value = 'basic'
- detailVisible.value = true
- alarmList.value = []
- if (row.equipmentId) {
- alarmLoading.value = true
- try {
- const res = await getAlarmDataPage(1, 20, { equipmentId: row.equipmentId, equipmentType: 'drainage' })
- alarmList.value = res.rows || res.data?.rows || res.data || []
- } catch (e) {
- alarmList.value = []
- } finally {
- alarmLoading.value = false
- }
- }
- }
- // ==================== 初始化 ====================
- onMounted(() => {
- loadData()
- })
- </script>
- <style scoped>
- .app-container {
- padding: 20px;
- }
- /* 搜索表单 */
- .search-form {
- margin-bottom: 16px;
- }
- /* 统计卡片 */
- .stat-cards {
- display: flex;
- gap: 16px;
- margin-bottom: 20px;
- }
- .stat-card {
- flex: 1;
- min-width: 0;
- }
- .stat-card :deep(.el-card__body) {
- padding: 16px 20px;
- }
- .stat-card-inner {
- display: flex;
- align-items: center;
- gap: 16px;
- }
- .stat-icon {
- width: 56px;
- height: 56px;
- border-radius: 12px;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- }
- .stat-blue .stat-icon {
- background: rgba(64, 158, 255, 0.1);
- color: #409EFF;
- }
- .stat-red .stat-icon {
- background: rgba(245, 108, 108, 0.1);
- color: #F56C6C;
- }
- .stat-orange .stat-icon {
- background: rgba(230, 162, 60, 0.1);
- color: #E6A23C;
- }
- .stat-green .stat-icon {
- background: rgba(103, 194, 58, 0.1);
- color: #67C23A;
- }
- .stat-info {
- flex: 1;
- min-width: 0;
- }
- .stat-value {
- font-size: 28px;
- font-weight: 700;
- line-height: 1.2;
- }
- .stat-blue .stat-value { color: #409EFF; }
- .stat-red .stat-value { color: #F56C6C; }
- .stat-orange .stat-value { color: #E6A23C; }
- .stat-green .stat-value { color: #67C23A; }
- .stat-label {
- font-size: 14px;
- color: #909399;
- margin-top: 4px;
- }
- /* 报警数高亮 */
- .alarm-has {
- color: #F56C6C;
- font-weight: 700;
- }
- /* 分页 */
- .pagination-wrap {
- display: flex;
- justify-content: flex-end;
- margin-top: 16px;
- }
- </style>
|