<template> <el-dialog v-model="props.visible" :title="title" :fullscreen="true" :close-on-click-modal="false" :close-on-press-escape="true" :show-close="true" custom-class="fullscreen-web-dialog" @close="handleClose" @open="handleOpen" > <div class="dialog-content"> <!-- 加载状态 --> <div v-if="loading" class="loading-container"> <el-icon class="loading-icon"><Loading /></el-icon> <span>网页加载中...</span> </div> <!-- 错误状态 --> <div v-if="error" class="error-container"> <el-icon class="error-icon"><Warning /></el-icon> <p>网页加载失败</p> <el-button type="primary" @click="reloadPage">重新加载</el-button> </div> <!-- 网页容器 - 使用 v-show 替代 v-if 避免重新创建 iframe --> <iframe v-show="!loading && !error" ref="iframeRef" :src="computedUrl" :key="iframeKey" class="web-iframe" @load="handleIframeLoad" @error="handleIframeError" frameborder="0" allowfullscreen ></iframe> </div> <!-- 底部操作栏 --> <template #footer> <div class="dialog-footer"> <el-button @click="reloadPage" :loading="loading"> <el-icon><Refresh /></el-icon> 刷新 </el-button> <el-button @click="openInNewTab"> <el-icon><Share /></el-icon> 在新标签页打开 </el-button> <el-button type="primary" @click="props.visible = false"> 关闭 </el-button> </div> </template> </el-dialog> </template> <script setup> import { ref, watch, computed, nextTick } from "vue"; import { Loading, Warning, Refresh, Share } from "@element-plus/icons-vue"; const props = defineProps({ visible: { type: Boolean, required: true, }, url: { type: String, required: true, }, title: { type: String, default: "网页预览", }, }); const emit = defineEmits(["update:visible", "close"]); const iframeRef = ref(null); const loading = ref(true); const error = ref(false); const iframeKey = ref(0); // 用于强制重新创建 iframe // 计算属性:添加时间戳避免缓存 const computedUrl = computed(() => { const timestamp = new Date().getTime(); // 只在URL没有参数时添加时间戳,避免破坏原有参数 if (props.url.includes("?")) { return `${props.url}&_t=${timestamp}`; } else { return `${props.url}?_t=${timestamp}`; } }); // 监听visible变化 watch( () => props.visible, (newVal) => { if (newVal) { resetState(); // 每次打开时重新创建 iframe iframeKey.value++; } else { // 关闭时清理状态 loading.value = false; error.value = false; } } ); // 对话框打开时的处理 const handleOpen = () => { resetState(); iframeKey.value++; }; // 处理iframe加载完成 const handleIframeLoad = () => { loading.value = false; error.value = false; console.log("iframe loaded successfully"); }; // 处理iframe加载错误 const handleIframeError = () => { loading.value = false; error.value = true; console.error("iframe loading failed"); }; // 重新加载页面 const reloadPage = () => { resetState(); iframeKey.value++; // 强制重新创建 iframe }; // 在新标签页打开 const openInNewTab = () => { window.open(props.url, "_blank"); }; // 处理关闭事件 const handleClose = () => { emit("update:visible", false); emit("close"); }; // 重置状态 const resetState = () => { loading.value = true; error.value = false; }; // 暴露方法给父组件 defineExpose({ reloadPage, openInNewTab, }); </script> <style scoped> .dialog-content { position: relative; height: calc(100vh - 140px); background: #f5f7fa; } .web-iframe { width: 100%; height: 100%; border: none; background: white; } .loading-container, .error-container { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; color: #606266; } .loading-icon { font-size: 48px; color: #409eff; margin-bottom: 16px; animation: rotating 2s linear infinite; } .error-icon { font-size: 48px; color: #f56c6c; margin-bottom: 16px; } .error-container p { margin: 16px 0; font-size: 16px; } .dialog-footer { display: flex; justify-content: flex-end; gap: 12px; } @keyframes rotating { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } </style> <style> .fullscreen-web-dialog .el-dialog__header { padding: 16px 20px; background: #f5f7fa; border-bottom: 1px solid #e4e7ed; } .fullscreen-web-dialog .el-dialog__body { padding: 0; } .fullscreen-web-dialog .el-dialog__footer { padding: 16px 20px; background: #f5f7fa; border-top: 1px solid #e4e7ed; } /* 确保对话框全屏 */ .fullscreen-web-dialog { width: 100vw !important; height: 100vh !important; margin: 0 !important; max-width: none !important; } .fullscreen-web-dialog .el-dialog__headerbtn { z-index: 2000; font-size: 20px; } </style> <template> <div class="compressor-monitor"> <el-button type="primary" @click="showFullscreenDialog" size="large"> 打开全屏网页弹窗 </el-button> <web-site v-model:visible="dialogVisible" :url="currentUrl" :title="dialogTitle" @close="handleDialogClose" /> </div> </template> <script setup> const dialogVisible = ref(false); const currentUrl = ref(""); const dialogTitle = ref(""); const showFullscreenDialog = () => { currentUrl.value = "https://www.baidu.com"; dialogTitle.value = "百度网页"; dialogVisible.value = true; }; const handleDialogClose = () => { console.log("弹窗已关闭"); }; </script> CREATE PROCEDURE SyncAlarmData AS BEGIN SET NOCOUNT ON; BEGIN TRY BEGIN TRANSACTION; -- 1. 先将新数据插入到本地alarm表(初始keep值) INSERT INTO GC.dbo.alarm (tagName, alarmState, keep, intime) SELECT tagName, alarmState, CASE WHEN alarmState = 'UN_ALM' THEN 0 ELSE 1 END AS keep, intime FROM runtime.dbo.alarm WHERE intime >= DATEADD(MINUTE, -1, GETDATE()); -- 2. 处理UN_TRN或ATC_RTN状态的数据 -- 找出所有需要处理的tagName(本次插入的RTN状态数据) ;WITH NewRTNAlarms AS ( SELECT DISTINCT tagName, intime FROM GC.dbo.alarm WHERE intime >= DATEADD(MINUTE, -1, GETDATE()) AND alarmState IN ('UN_TRN', 'ATC_RTN') ) UPDATE a SET keep = 1 FROM GC.dbo.alarm a INNER JOIN NewRTNAlarms r ON a.tagName = r.tagName WHERE a.keep = 0 AND a.intime <= r.intime; -- 只更新RTN时间之前的数据 -- 3. 处理特殊情况:如果RTN后面有UN_ALM,保持UN_ALM的keep=0 -- (因为上一步已经处理了RTN时间之前的数据,RTN时间之后的UN_ALM保持0不变) COMMIT TRANSACTION; END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; -- 记录错误信息 DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(); DECLARE @ErrorSeverity INT = ERROR_SEVERITY(); DECLARE @ErrorState INT = ERROR_STATE(); RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState); END CATCH END GO
留言评论