| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311 |
- <template>
- <div class="dashboard-container">
- <Skeleton v-if="loading" active class="p-20px"></Skeleton>
- <!-- 内容区域 -->
- <div class="content-area" v-if="!loading">
- <!-- 顶部信息卡片 -->
- <div class="top-info">
- <div class="info-card">
- <div class="card-title">
- <div class="info-details">
- <div class="label">{{ basicInfo.mineName }}</div>
- <!-- <div class="value">西川煤矿分公司</div> -->
- <div class="tag" :style="{ backgroundColor: getAlarmColor(basicInfo.alarmLevel), color: '#fff' }">{{
- getRiskText(basicInfo.alarmLevel)
- }}</div>
- </div>
- <div>
- <a-button class="btn" @click="handleGoToPageQuery('/warningAnalysis/connectAnalysis')">数据看板</a-button>
- </div>
- <div class="info-border">
- <div class="info-border-icon"></div>
- <div class="info-border-line"></div>
- <div class="info-border-icon"></div>
- </div>
- </div>
- <div class="card-details">
- <div v-for="item in basicInfoColumns" :key="item.key" class="info-card-item">
- <div class="card-label">{{ item.label }}</div>
- <div class="card-value-wrapper">
- <span
- v-if="['accessStatus', 'status', 'gasLevelName', 'alarmLevel', 'gjMineStatus'].includes(item.key)"
- class="status-dot"
- :style="{ backgroundColor: getBasicInfoColor(item.key), boxShadow: `0 0 10px ${getBasicInfoColor(item.key)}` }"
- ></span>
- <span class="card-value-text" :style="{ color: getBasicInfoColor(item.key) }">
- {{ getBasicInfoValue(item.key) }}
- </span>
- </div>
- <div class="card-border">
- <div class="card-border-icon"></div>
- <div class="card-border-line"></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 预警统计 -->
- <div class="warning-statistics">
- <div class="statistics-header">
- <div class="title">预警统计</div>
- <div class="btn-group">
- <!-- <button class="btn">预警级别</button> -->
- </div>
- </div>
- <div class="statistics-content">
- <div class="stat-item high-risk">
- <div class="icon">
- <div class="icon-top"></div>
- <div class="icon-bottom"></div>
- </div>
- <div class="text">高风险<span class="text-sub">(需立即处理)</span></div>
- <div class="count">{{ get(alarmStatistics, 'alarm4', '-') }}</div>
- </div>
- <div class="stat-item medium-risk">
- <div class="icon">
- <div class="icon-top"></div>
- <div class="icon-bottom"></div>
- </div>
- <div class="text">较高风险<span class="text-sub"></span></div>
- <div class="count">{{ get(alarmStatistics, 'alarm3', '-') }}</div>
- </div>
- <div class="stat-item normal-risk">
- <div class="icon">
- <div class="icon-top"></div>
- <div class="icon-bottom"></div>
- </div>
- <div class="text">一般风险<span class="text-sub"></span></div>
- <div class="count">{{ get(alarmStatistics, 'alarm2', '-') }}</div>
- </div>
- <div class="stat-item low-risk">
- <div class="icon">
- <div class="icon-top"></div>
- <div class="icon-bottom"></div>
- </div>
- <div class="text">低风险<span class="text-sub"></span></div>
- <div class="count">{{ get(alarmStatistics, 'alarm1', '-') }}</div>
- </div>
- </div>
- </div>
- <!-- 预警数据详情 -->
- <div class="warning-details">
- <div class="details-header">
- <div class="title">预警数据详情</div>
- <div class="btn-group">
- <button class="btn" @click="collapseAll">收起所有分组</button>
- <button class="btn" @click="expandAll">展开详情</button>
- </div>
- </div>
- <div class="details-content">
- <Empty v-if="!goafMonitorData.length"></Empty>
- <!-- 第一个预警项 -->
- <div v-for="(item, index) in goafMonitorData" :key="index" class="warning-item">
- <div class="item-header">
- <div class="header-left">
- <div class="icon"></div>
- <div class="name">老空区密闭名称: {{ item.devicePos }}</div>
- <div class="risk-level" :style="{ backgroundColor: getAlarmColor(item.alarmLevel), color: '#fff' }">
- {{ getRiskText(item.alarmLevel) }}
- </div>
- </div>
- <a-button class="expand-btn" @click="toggleExpand(index)">
- {{ isExpanded(index) ? '收起' : '展开' }}
- <div class="arrow-icon-wrapper">
- <div class="arrow-icon" :class="{ rotate: isExpanded(index) }"></div>
- </div>
- </a-button>
- </div>
- <div class="item-body">
- <div class="data-row">
- <div v-for="(col, colIndex) in dataColumns" :key="colIndex" class="data-col">
- <div class="col-title">{{ col.label }}</div>
- <div class="col-value" :style="{ color: getColValueColor(col, item) }">
- <span
- v-if="col.type !== 'text'"
- class="status-dot"
- :style="{
- backgroundColor: getColValueColor(col, item),
- boxShadow: `0 0 10px ${getColValueColor(col, item)}`,
- }"
- ></span>
- {{ getColDisplayText(col, item) }}
- </div>
- <div class="col-icon"></div>
- </div>
- </div>
- </div>
- <div class="monitoring-indicators" v-show="isExpanded(index)">
- <div class="indicator-group">
- <div class="group-title">
- <div class="title-icon-top"></div>
- <div class="title-icon-bottom"></div>
- <div class="title-content">
- 密闭墙内<br />
- 监测指标
- </div>
- </div>
- <div class="indicator-area">
- <div v-for="(ind, indIndex) in indicatorColumns" :key="'inner-' + indIndex" class="indicator-item">
- <div class="label">{{ ind.label }}:</div>
- <!-- 墙内数据直接取 item[key],例如 item.coVal -->
- <div class="value" :title="getDataValue(item, ind.key)">{{ getDataValue(item, ind.key) }} {{ ind.unit }}</div>
- </div>
- </div>
- </div>
- <div class="indicator-group">
- <div class="group-title">
- <div class="title-icon-top icon-outer"></div>
- <div class="title-icon-bottom"></div>
- <div class="title-content">
- 密闭墙外<br />
- 监测指标
- </div>
- </div>
- <div class="indicator-area">
- <div v-for="(ind, indIndex) in indicatorColumns" :key="'outer-' + indIndex" class="indicator-item">
- <div class="label">{{ ind.label }}:</div>
- <!-- 墙外数据+ Out item[key],例如 item.coValOut -->
- <div class="value" :title="getDataValue(item, ind.key + 'Out')">{{ getDataValue(item, ind.key + 'Out') }} {{ ind.unit }}</div>
- </div>
- </div>
- </div>
- <!-- <div class="indicator-group">
- <div class="group-title">
- <div class="title-icon-top icon-result"></div>
- <div class="title-icon-bottom"></div>
- <div class="title-content"> 预警结果 </div>
- </div>
- <div class="indicator-area indicator-result">
- <div v-for="(res, resIndex) in resultColumns" :key="'result-' + resIndex" class="indicator-item">
- <div class="label">{{ res.label }}:</div>
- <div v-if="res.key == 'alarmLevel'" :title="getRiskText(item.alarmLevel)" class="value">{{ getRiskText(item.alarmLevel) }}</div>
- <div v-else class="value" :title="getDataValue(item, res.key)">{{ getDataValue(item, res.key) }}</div>
- </div>
- <div class="indicator-item placeholder-item"></div>
- </div>
- </div> -->
- </div>
- </div>
- </div>
- </div>
- <!-- 异常超限报警 -->
- <div class="abnormal-alarm">
- <div class="alarm-header">
- <div class="title">异常超限报警</div>
- <div class="btn-group">
- <!-- <button class="btn">收起图表</button> -->
- </div>
- </div>
- <div class="alarm-content">
- <div v-for="(alarm, index) in alarmColumns" :key="index" class="alarm-item">
- <div class="alarm-name">{{ alarm.label }}</div>
- <div class="alarm-count">{{ get(mineAlarmData, alarm.key, '-') }}</div>
- <div class="alarm-border">
- <div class="alarm-border-icon"></div>
- <div class="alarm-border-line"></div>
- </div>
- <div class="alarm-border-bottom"></div>
- </div>
- </div>
- </div>
- <!-- 历史数据折线图 -->
- <div class="historical-data">
- <div class="chart-header">
- <div class="title">历史数据分析图表</div>
- <div class="btn-group">
- <button class="btn" @click="toggleChartVisibility">
- {{ isChartVisible ? '收起图表' : '展开图表' }}
- </button>
- </div>
- </div>
- <div class="chart-content" v-show="isChartVisible">
- <ConnectAnalysis ref="connectAnalysisRef" />
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { useRouter } from 'vue-router';
- // import { useAppStore } from '/@/store/modules/app';
- import { ref, watch } from 'vue';
- import { useMineDepartmentStore } from '/@/store/modules/mine';
- import { getGoafAlarmNum, getGoafData, getMineData /*, getProvinceAlarm */ } from '../overhaul.api';
- import { StatusColorEnum } from '/@/enums/jeecgEnum';
- import ConnectAnalysis from '/@/views/analysis/warningAnalysis/connectAnalysis/index.vue';
- import { getOverLimitNum } from '../../SealedGoaf/sealedGoaf.api';
- import { get } from 'lodash-es';
- import { Empty, Skeleton } from 'ant-design-vue';
- // const appStore = useAppStore();
- const mineStore = useMineDepartmentStore();
- // 路由实例
- const router = useRouter();
- // 1. 定义数据类型接口
- interface GoafMonitorItem {
- devicePos?: string;
- [key: string]: any; // 允许其他动态属性
- }
- /**
- * 风险等级映射配置
- */
- const RISK_LEVEL_MAP: Record<string, { text: string; color: string }> = {
- '4': { text: '高风险', color: StatusColorEnum.red },
- '3': { text: '较高风险', color: StatusColorEnum.gold },
- '2': { text: '一般风险', color: StatusColorEnum.yellow },
- '1': { text: '低风险', color: StatusColorEnum.blue },
- '0': { text: '无风险', color: '#333' }, // 假设 0 为无风险或默认
- };
- // 顶部的基础信息部分
- const basicInfoColumns = [
- { label: '组织机构', key: 'parentArea' },
- { label: '瓦斯等级', key: 'gasLevelName' },
- { label: '煤层自燃倾向性', key: 'coalSeamLevel' },
- { label: '生产状态', key: 'gjMineStatus' },
- { label: '预警结果', key: 'alarmLevel' },
- { label: '预警时间', key: 'earliestTime' },
- { label: '持续时间', key: 'chixuTime' },
- { label: '接入状态', key: 'accessStatus' },
- { label: '数据联网状态', key: 'status' },
- { label: '设备数量', key: 'accessGoafNum' },
- ];
- // 1. 预警数据详情 - 顶部指标列配置
- const dataColumns = [
- { label: '密闭墙内自燃发火隐患', key: 'fireAlarm.alarmName', colorKey: 'fireAlarm.alarmLevel', type: 'alarm' },
- { label: '密闭墙外自燃发火隐患', key: 'fireAlarmOut.alarmName', colorKey: 'fireAlarmOut.alarmLevel', type: 'alarm' },
- { label: '爆炸三角', key: 'explosionAlarm.alarmName', colorKey: 'explosionAlarm.alarmLevel', type: 'alarm' },
- { label: '压差预警', key: 'sourcePressureAlarm.alarmName', colorKey: 'sourcePressureAlarm.alarmLevel', type: 'alarm' },
- { label: '漏风状态判定', key: 'leakageAlarm.alarmName', colorKey: 'leakageAlarm.alarmLevel', type: 'alarm' },
- { label: '设备状态', key: 'linkStatus', type: 'status' },
- { label: '检查时间', key: 'readTime', type: 'text' },
- ];
- // 2. 监测指标通用配置 (用于墙内和墙外)
- const indicatorColumns = [
- { label: 'CO', key: 'coVal', unit: 'ppm' },
- { label: 'CO2', key: 'co2Val', unit: '%' },
- { label: 'CH4', key: 'ch4Val', unit: '%' },
- { label: 'O2', key: 'o2Val', unit: '%' },
- { label: 'C2H2', key: 'c2h2Val', unit: 'ppm' },
- { label: 'C2H4', key: 'c2h4Val', unit: 'ppm' },
- { label: '温度', key: 'temperature', unit: '°C' },
- ];
- // 3. 预警结果配置(已注释,对应模板块已隐藏)
- // const resultColumns = [
- // { label: '数据来源', key: 'readTime', value: '最近2天' },
- // { label: '预警结果', key: 'alarmLevel', value: '异常' },
- // ];
- // 4. 异常超限报警配置
- const alarmColumns = [
- { label: '甲烷超限', key: 'ch4Val' },
- { label: '氧气超限', key: 'o2Val' },
- { label: '一氧化碳超限', key: 'coVal' },
- { label: '二氧化碳超限', key: 'co2Val' },
- { label: '乙烯超限', key: 'c2h4Val' },
- { label: '乙炔超限', key: 'c2h2Val' },
- { label: '压差超限', key: 'sourcePressure' },
- { label: '温度超限', key: 'temperature' },
- ];
- const basicInfo = ref<any>({}); //煤矿基础信息数据
- const alarmStatistics = ref<any>({}); //预警统计数据
- const goafMonitorData = ref<GoafMonitorItem[]>([]); //密闭监测详情数据
- const mineAlarmData = ref<any>({}); // 煤矿预警数据
- // const connectAnalysisRef = ref<any>(null); // 连接分析组件实例
- const isChartVisible = ref(true); // 控制图表显示/隐藏的状态
- const loading = ref(false);
- // 1. 用于存储展开状态的索引集合 (key: index, value: boolean)
- const expandedIndices = ref<Record<number, boolean>>({});
- // 2. 切换展开/收起状态的方法
- const toggleExpand = (index: number) => {
- expandedIndices.value[index] = !expandedIndices.value[index];
- };
- // 3. 判断是否展开
- const isExpanded = (index: number) => {
- return !!expandedIndices.value[index];
- };
- // 4. 展开所有详情
- const expandAll = () => {
- goafMonitorData.value.forEach((_, index) => {
- expandedIndices.value[index] = true;
- });
- };
- // 5. 收起所有分组
- const collapseAll = () => {
- // 清空对象即可,或者遍历设为 false
- expandedIndices.value = {};
- };
- // 切换图表显示状态
- const toggleChartVisibility = () => {
- isChartVisible.value = !isChartVisible.value;
- };
- /**
- * 获取设备状态信息 (文本和颜色)
- * @param status 0: 断开, 1: 正常
- */
- const getlinkStatusInfo = (status?: number | string) => {
- if (status === 1 || status === '1') {
- return { text: '正常', color: '#52c41a' }; // 绿色
- }
- return { text: '断开', color: '#ff4d4f' }; // 红色
- };
- /**
- * 获取列显示的文本
- */
- const getColDisplayText = (col: any, item: any) => {
- const rawValue = getDataValue(item, col.key);
- if (col.type === 'status') {
- return getlinkStatusInfo(rawValue).text;
- }
- // 默认直接返回原始值或经过 getDataValue 处理后的值
- return rawValue;
- };
- /**
- * 获取列显示的颜色
- */
- const getColValueColor = (col: any, item: any) => {
- // 如果是报警类型,使用原有的报警颜色逻辑
- if (col.type === 'alarm' && col.colorKey) {
- return getAlarmColor(getDataValue(item, col.colorKey));
- }
- // 如果是设备状态类型,使用状态颜色逻辑
- if (col.type === 'status') {
- return getlinkStatusInfo(getDataValue(item, col.key)).color;
- }
- // 默认黑色
- return '#333';
- };
- /**
- * 获取风险等级对应的文本
- * @param level 报警级别 '1', '2', '3', '4'
- */
- const getRiskText = (level?: string | number) => {
- if (!level && level !== 0) return '-';
- return RISK_LEVEL_MAP[String(level)]?.text || '-';
- };
- /**
- * 根据点分字符串路径获取对象值 (例如: 'fireAlarm.alarmName')
- * @param item 数据对象
- * @param path 路径字符串
- * @param defaultValue 默认值
- */
- const getDataValue = (item: any, path: string, defaultValue: string = '-') => {
- if (!item || !path) return defaultValue;
- const val = path.split('.').reduce((acc, part) => acc && acc[part], item);
- return val ?? defaultValue;
- };
- /**
- * 获取报警颜色
- * @param level 报警级别 '1', '2', '3', '4'
- */
- const getAlarmColor = (level?: string | number) => {
- if (!level && level !== 0) return '#333'; // 默认颜色
- return RISK_LEVEL_MAP[String(level)]?.color;
- };
- /**
- * 获取基础信息的显示内容(包含文本和颜色)
- */
- const getBasicInfoDisplay = (key: string) => {
- const value = basicInfo.value[key];
- // 默认返回黑色文本
- const defaultResult = { text: value ?? '-', color: '#333' };
- if (key === 'accessStatus') {
- // 1: 已接入 (绿色), 其他: 未接入 (红色)
- return value === 1 ? { text: '已接入', color: '#52c41a' } : { text: '未接入', color: StatusColorEnum.red };
- }
- if (key === 'status') {
- // 1: 在线 (绿色), 其他: 离线 (红色)
- return value === 1 ? { text: '在线', color: '#52c41a' } : { text: '离线', color: StatusColorEnum.red };
- }
- if (key === 'alarmLevel') {
- // 根据风险等级获取颜色
- const levelStr = String(value);
- const riskInfo = RISK_LEVEL_MAP[levelStr];
- if (riskInfo) {
- return { text: riskInfo.text, color: riskInfo.color };
- }
- return { text: '-', color: '#333' };
- }
- if (key === 'gasLevelName') {
- if (!value) return { text: value ?? '-', color: '#333' };
- // 瓦斯等级特殊处理
- const val = String(value);
- if (val.includes('低瓦斯')) {
- return { text: val, color: StatusColorEnum.blue }; // 蓝色
- } else if (val.includes('高瓦斯')) {
- return { text: val, color: StatusColorEnum.gold }; // 橙色/金色
- } else if (val.includes('突出')) {
- return { text: val, color: StatusColorEnum.red }; // 红色
- }
- return { text: val, color: '#333' };
- }
- if (key === 'gjMineStatus') {
- if (!value) return { text: value ?? '-', color: '#333' };
- // 生产状态特殊处理
- const val = String(value);
- if (val.includes('正常生产')) {
- return { text: val, color: '#52c41a' }; // 绿色
- } else if (val.includes('拟建')) {
- return { text: val, color: StatusColorEnum.blue }; // 蓝色
- } else {
- // 其余状态均显示绿色
- return { text: val ?? '-', color: StatusColorEnum.red };
- }
- }
- return defaultResult;
- };
- /**
- * 获取基础信息值的文本(兼容旧逻辑,如果只需要文本)
- */
- const getBasicInfoValue = (key: string) => {
- return getBasicInfoDisplay(key).text;
- };
- /**
- * 获取基础信息值的颜色
- */
- const getBasicInfoColor = (key: string) => {
- return getBasicInfoDisplay(key).color;
- };
- /**
- * 通用页面跳转方法
- * @param record 当前行数据
- * @param path 目标路径
- */
- function handleGoToPageQuery(path: string) {
- router
- .push({
- path,
- })
- .catch((err) => {
- console.error('跳转失败:', err);
- });
- }
- /**
- * 计算持续时间
- * @param earliestTimeStr 开始时间字符串
- * @param latestReadTimeStr 结束时间字符串
- * @returns 格式化后的持续时间字符串,如 "1天2小时30分钟",无效则返回 "-"
- */
- const calculateDuration = (earliestTimeStr?: string, latestReadTimeStr?: string): string => {
- if (!earliestTimeStr || !latestReadTimeStr) {
- return '-';
- }
- const earliestTime = new Date(earliestTimeStr).getTime();
- const latestReadTime = new Date(latestReadTimeStr).getTime();
- if (isNaN(earliestTime) || isNaN(latestReadTime)) {
- return '-';
- }
- const diffMs = latestReadTime - earliestTime;
- // 如果时间差为负数,返回 '-'
- if (diffMs < 0) {
- return '-';
- }
- // 转换为天、小时、分钟
- const days = Math.floor(diffMs / (1000 * 60 * 60 * 24));
- const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
- const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
- let timeStr = '';
- if (days > 0) {
- timeStr += `${days}天`;
- }
- if (hours > 0 || days > 0) {
- timeStr += `${hours}小时`;
- }
- // 如果只有分钟,或者有天/小时,都加上分钟
- timeStr += `${minutes}分钟`;
- return timeStr;
- };
- async function fetchLeafData() {
- try {
- // 异步获取所有接口数据(并行请求提升性能)
- const [goafAlarmNum, goafData, mineData, alarmData] = await Promise.all([
- getGoafAlarmNum({ deptId: mineStore.getDepartId }), // 预警统计
- getGoafData({ deptId: mineStore.getDepartId }), // 密闭监测数据
- getMineData({ deptId: mineStore.getDepartId }), // 煤矿基础信息数据
- // getProvinceAlarm({ deptId: mineStore.getDepartId }), // 预警信息列表
- getOverLimitNum({ deptId: mineStore.getDepartId }),
- ]);
- alarmStatistics.value = goafAlarmNum[0] || {};
- goafMonitorData.value = goafData.records;
- // basicInfo.value = mineData.records[0];
- mineAlarmData.value = alarmData.reduce((obj, e) => {
- obj[e.alarmFiled] = e.num;
- return obj;
- }, {});
- // 处理煤矿基础信息并计算持续时间
- const mineRecord = mineData.records[0];
- if (mineRecord) {
- // 获取最早预警时间
- const earliestTimeStr = mineRecord.earliestTime;
- // 获取最新的一条密闭监测数据的读取时间
- const latestReadTimeStr = goafData.records?.[0]?.readTime;
- // 调用抽取的方法计算持续时间
- mineRecord.chixuTime = calculateDuration(earliestTimeStr, latestReadTimeStr);
- basicInfo.value = mineRecord;
- } else {
- basicInfo.value = {};
- }
- // nextTick(() => {
- // if (connectAnalysisRef.value && typeof connectAnalysisRef.value.generateChart === 'function') {
- // connectAnalysisRef.value.generateChart();
- // }
- // });
- } catch (error) {
- console.error('数据获取/配置更新失败:', error);
- }
- }
- watch(
- () => mineStore.getDepartId,
- async () => {
- loading.value = true;
- await fetchLeafData();
- loading.value = false;
- },
- { immediate: true }
- );
- // 页面逻辑代码
- </script>
- <style scoped>
- .dashboard-container {
- display: flex;
- flex-direction: column;
- height: 100%;
- overflow: scroll;
- }
- .content-area {
- flex: 1;
- padding: 20px;
- background-color: #f0f8ff;
- }
- .top-info {
- width: 100%;
- height: 200px;
- margin-bottom: 20px;
- }
- .info-card {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: row;
- background-image: url('/@/assets/images/overHaul/leafPage/info-card-bg.png');
- background-repeat: no-repeat;
- background-size: 100%;
- border-radius: 8px;
- padding: 20px;
- }
- .card-title {
- width: 20%;
- position: relative;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- padding: 8px 10px 8px 50px;
- .btn {
- color: #fff;
- background-color: #2b6ff0;
- &:hover {
- background-color: #397af3;
- }
- }
- }
- .info-border {
- position: absolute;
- top: 20px;
- left: 20px;
- .info-border-icon {
- width: 16px;
- height: 16px;
- background-image: url('/@/assets/images/overHaul/leafPage/info-card-icon1.svg');
- background-repeat: no-repeat;
- background-size: 100%;
- }
- .info-border-line {
- width: 1px;
- height: 95px;
- border-left: 2px dotted #397af3;
- margin-left: 7px;
- }
- }
- .info-details {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- padding: 8px 0;
- .label {
- font-size: 16px;
- color: #000;
- }
- .value {
- font-size: 16px;
- color: #000;
- }
- .tag {
- width: fit-content;
- height: 24px;
- padding: 2px 8px;
- border-radius: 15px;
- font-size: 12px;
- background-color: #ff6b6b;
- color: white;
- }
- }
- .card-details {
- width: 80%;
- display: grid;
- grid-template-columns: repeat(5, 1fr);
- gap: 8px;
- }
- .info-card-item {
- max-width: 245px;
- height: 70px;
- position: relative;
- padding: 8px 10px 8px 40px;
- background-color: #f1f7ff;
- border-radius: 4px;
- text-align: left;
- }
- .card-border {
- width: 20px;
- height: 50px;
- position: absolute;
- top: 14px;
- left: 15px;
- .card-border-icon {
- width: 16px;
- height: 16px;
- background-image: url('/@/assets/images/overHaul/leafPage/info-card-icon.svg');
- background-repeat: no-repeat;
- background-size: 100%;
- }
- .card-border-line {
- width: 1px;
- height: 30px;
- border-left: 2px dotted #397af3;
- margin-left: 7px;
- }
- }
- .card-label {
- font-size: 16px;
- color: #000;
- font-weight: bold;
- margin-bottom: 8px;
- }
- .card-value-wrapper {
- display: flex;
- align-items: center;
- gap: 6px;
- }
- .status-dot {
- width: 8px;
- height: 8px;
- border-radius: 50%;
- display: inline-block;
- flex-shrink: 0;
- }
- .card-value-text {
- font-size: 14px;
- color: #333;
- font-weight: bold;
- }
- .warning-statistics {
- background-color: #ffffff;
- margin-bottom: 20px;
- padding: 10px 12px;
- border-radius: 4px;
- }
- .statistics-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 10px;
- }
- .title {
- font-size: 16px;
- font-weight: bold;
- color: #333;
- }
- .btn-group {
- display: flex;
- gap: 8px;
- }
- .btn {
- color: #2b6ff0;
- padding: 6px 12px;
- border: 1px solid #2b6ff0;
- border-radius: 4px;
- background-color: #e9f0fe;
- cursor: pointer;
- font-size: 12px;
- }
- .btn:hover {
- background-color: #f5f5f5;
- }
- .statistics-content {
- display: flex;
- gap: 50px;
- }
- .stat-item {
- flex: 1;
- min-height: 80px;
- padding: 16px 50px 10px 90px;
- text-align: left;
- position: relative;
- overflow: hidden;
- background-image: url('/@/assets/images/overHaul/leafPage/high-risk-bg.png');
- background-repeat: no-repeat;
- background-size: 100%;
- .icon {
- position: absolute;
- top: 15px;
- left: 20px;
- }
- .text {
- font-size: 16px;
- color: #000;
- font-weight: bold;
- .text-sub {
- font-size: 12px;
- color: #989587;
- }
- }
- .count {
- font-size: 24px;
- font-weight: bold;
- }
- .icon-top {
- width: 40px;
- height: 40px;
- background-image: url('/@/assets/images/overHaul/leafPage/high-risk-icon1.svg');
- background-repeat: no-repeat;
- background-size: 100%;
- }
- .icon-bottom {
- width: 40px;
- height: 20px;
- background-image: url('/@/assets/images/overHaul/leafPage/high-risk-icon2.png');
- background-repeat: no-repeat;
- background-size: 100%;
- margin-top: -5px;
- }
- }
- .stat-item.high-risk {
- background-image: url('/@/assets/images/overHaul/leafPage/high-risk-bg.png');
- .icon-top {
- background-image: url('/@/assets/images/overHaul/leafPage/high-risk-icon1.svg');
- }
- .icon-bottom {
- background-image: url('/@/assets/images/overHaul/leafPage/high-risk-icon2.png');
- }
- .count {
- color: #ff0000;
- }
- }
- .stat-item.medium-risk {
- background-image: url('/@/assets/images/overHaul/leafPage/medium-risk-bg.png');
- .icon-top {
- background-image: url('/@/assets/images/overHaul/leafPage/medium-risk-icon1.svg');
- }
- .icon-bottom {
- background-image: url('/@/assets/images/overHaul/leafPage/medium-risk-icon2.png');
- }
- .count {
- color: #ff7700;
- }
- }
- .stat-item.normal-risk {
- background-image: url('/@/assets/images/overHaul/leafPage/normal-risk-bg.png');
- .icon-top {
- background-image: url('/@/assets/images/overHaul/leafPage/normal-risk-icon1.svg');
- }
- .icon-bottom {
- background-image: url('/@/assets/images/overHaul/leafPage/normal-risk-icon2.png');
- }
- .count {
- color: #d5c702;
- }
- }
- .stat-item.low-risk {
- background-image: url('/@/assets/images/overHaul/leafPage/low-risk-bg.png');
- .icon-top {
- background-image: url('/@/assets/images/overHaul/leafPage/low-risk-icon1.svg');
- }
- .icon-bottom {
- background-image: url('/@/assets/images/overHaul/leafPage/low-risk-icon2.png');
- }
- .count {
- color: #0070ff;
- }
- }
- .warning-details {
- background-color: #ffffff;
- margin-bottom: 20px;
- padding: 10px 12px;
- border-radius: 4px;
- }
- .details-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
- }
- .details-content {
- max-height: 350px;
- overflow-y: auto;
- scroll-snap-type: y mandatory;
- }
- .warning-item {
- margin-bottom: 16px;
- background-color: rgba(218, 234, 251, 0.5);
- border-radius: 8px;
- padding: 16px 10px;
- scroll-snap-align: start;
- }
- .item-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding-bottom: 10px;
- margin-bottom: 14px;
- border-bottom: 1px solid rgba(43, 111, 240, 0.2);
- .icon {
- width: 16px;
- height: 16px;
- background-image: url('/@/assets/images/overHaul/leafPage/info-card-icon1.svg');
- background-repeat: no-repeat;
- background-size: 100%;
- }
- .name {
- font-size: 16px;
- font-weight: bold;
- color: #333;
- margin: 0 15px 0px 5px;
- }
- .risk-level {
- width: fit-content;
- height: 24px;
- padding: 2px 8px;
- border-radius: 15px;
- font-size: 12px;
- background-color: #ff6b6b;
- color: white;
- }
- .header-left {
- display: flex;
- align-items: center;
- }
- .expand-btn {
- color: #2b6ff0;
- display: flex;
- align-items: center;
- gap: 4px;
- padding: 6px 12px;
- border: 1px solid #2b6ff0;
- border-radius: 4px;
- background-color: #e9f0fe;
- cursor: pointer;
- font-size: 12px;
- }
- .expand-btn:hover {
- color: #1a5cc8;
- }
- .arrow-icon-wrapper {
- width: 16px;
- height: 16px;
- position: relative;
- display: inline-block;
- }
- .arrow-icon {
- width: 16px;
- height: 16px;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background-image: url('/@/assets/images/overHaul/leafPage/icon-down1.png');
- background-repeat: no-repeat;
- background-size: 100% 100%;
- transition: transform 0.3s ease;
- }
- .arrow-icon.rotate {
- transform: translate(-50%, -50%) rotate(180deg);
- }
- }
- .data-row {
- display: grid;
- grid-template-columns: repeat(7, 1fr);
- gap: 12px;
- }
- .data-col {
- width: 100%;
- height: 80px;
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: start;
- /* justify-content: center; */
- padding: 0 16px 0 30px;
- background-image: url('/@/assets/images/overHaul/leafPage/warning-item-bg.png');
- background-repeat: no-repeat;
- background-size: 100% 100%;
- border-radius: 4px;
- font-size: 12px;
- .col-title {
- color: #000;
- height: 24px;
- line-height: 30px;
- font-size: 14px;
- margin-bottom: 5px;
- }
- .col-value {
- color: #000;
- font-size: 14px;
- .status-dot {
- width: 8px;
- height: 8px;
- border-radius: 50%;
- display: inline-block;
- }
- }
- .col-icon {
- position: absolute;
- top: 8px;
- left: 10px;
- width: 18px;
- height: 18px;
- background-image: url('/@/assets/images/overHaul/leafPage/info-card-icon.svg');
- background-repeat: no-repeat;
- background-size: 100%;
- }
- }
- .monitoring-indicators {
- display: flex;
- gap: 20px;
- margin-top: 20px;
- }
- .indicator-group {
- display: flex;
- background-color: white;
- border-radius: 8px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- min-width: 0;
- flex: 1;
- }
- .indicator-group:nth-child(1) {
- flex: 4;
- }
- .indicator-group:nth-child(2) {
- flex: 4;
- }
- .indicator-group:nth-child(3) {
- flex: 2;
- }
- .group-title {
- width: 120px;
- display: flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
- justify-content: center;
- font-size: 14px;
- font-weight: bold;
- color: #000;
- background-color: rgba(192, 222, 255, 0.6);
- .title-icon-top {
- width: 30px;
- height: 30px;
- background-image: url('/@/assets/images/overHaul/leafPage/icon-top1.svg');
- background-repeat: no-repeat;
- background-size: 100%;
- margin-bottom: -5px;
- }
- .icon-outer {
- background-image: url('/@/assets/images/overHaul/leafPage/icon-top2.svg');
- }
- .icon-result {
- background-image: url('/@/assets/images/overHaul/leafPage/icon-top3.svg');
- }
- .title-icon-bottom {
- width: 50px;
- height: 23px;
- background-image: url('/@/assets/images/overHaul/leafPage/icon-bottom.png');
- background-repeat: no-repeat;
- background-size: 100%;
- }
- }
- .indicator-area {
- width: calc(100% - 120px);
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 10px;
- padding: 10px 16px;
- }
- .indicator-result {
- grid-template-columns: repeat(1, 1fr);
- }
- .indicator-item {
- height: 30px;
- line-height: 30px;
- display: flex;
- justify-content: space-between;
- background: linear-gradient(90deg, rgba(192, 222, 255, 0.5) 0%, rgba(192, 222, 255, 0.2) 100%);
- border-radius: 4px;
- margin-bottom: 8px;
- padding: 0 4px;
- .value {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- min-width: 0;
- flex: 1;
- text-align: right;
- }
- }
- /* 预警结果只有两行,用来占位的 item */
- .placeholder-item {
- visibility: hidden;
- height: 30px;
- margin-bottom: 8px;
- background: transparent;
- pointer-events: none;
- }
- .indicator-result .indicator-item:last-of-type {
- margin-bottom: 8px;
- }
- .indicator-item:last-child {
- border-bottom: none;
- }
- .abnormal-alarm {
- background-color: #fff;
- margin-bottom: 20px;
- padding: 10px 12px;
- border-radius: 4px;
- }
- .alarm-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
- }
- .alarm-content {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- }
- .alarm-item {
- flex: 1;
- min-width: 120px;
- height: 70px;
- position: relative;
- padding: 8px 10px 8px 40px;
- background-color: rgba(215, 233, 253, 0.9);
- border-radius: 4px;
- text-align: left;
- }
- .alarm-name {
- font-size: 16px;
- color: #000;
- font-weight: bold;
- margin-bottom: 8px;
- }
- .alarm-count {
- font-size: 14px;
- color: #333;
- font-weight: bold;
- }
- .alarm-border {
- width: 20px;
- height: 50px;
- position: absolute;
- top: 14px;
- left: 15px;
- .alarm-border-icon {
- width: 16px;
- height: 16px;
- background-image: url('/@/assets/images/overHaul/leafPage/info-card-icon.svg');
- background-repeat: no-repeat;
- background-size: 100%;
- }
- .alarm-border-line {
- width: 1px;
- height: 30px;
- border-left: 2px dotted #397af3;
- margin-left: 7px;
- }
- }
- .alarm-border-bottom {
- width: 30px;
- height: 30px;
- background-image: url('/@/assets/images/overHaul/leafPage/alarm-card-icon.png');
- background-repeat: no-repeat;
- background-size: 100%;
- position: absolute;
- right: 0;
- bottom: 0;
- }
- .historical-data {
- background-color: #fff;
- margin-bottom: 20px;
- padding: 10px 12px;
- border-radius: 4px;
- }
- .chart-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .chart-content {
- padding: 0;
- height: 600px;
- overflow: hidden;
- position: relative;
- }
- /* 深度选择器:重置 ConnectAnalysis 的样式以适配嵌入环境 */
- :deep(.connectAnalysis) {
- margin: 0 !important;
- width: 100% !important;
- height: 100% !important;
- border: none !important;
- box-shadow: none !important;
- padding: 0 !important;
- display: flex;
- flex-direction: column;
- }
- :deep(.filter-area) {
- width: 100%;
- }
- :deep(.echart-box) {
- /* 让图表区域占据剩余所有高度 */
- flex: 1;
- height: auto !important;
- display: flex;
- flex-direction: column;
- padding: 10px;
- }
- :deep(.echart-content) {
- flex: 1;
- height: auto !important;
- min-height: 300px;
- }
- </style>
|