|
|
@@ -350,7 +350,9 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div class="detail-content">
|
|
|
+ <div class="detail-content-wrapper">
|
|
|
+ <div class="detail-main-area">
|
|
|
+ <div class="detail-content">
|
|
|
<div
|
|
|
v-if="isLoadingDetail || isImageLoading"
|
|
|
class="loading-overlay"
|
|
|
@@ -420,38 +422,6 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div
|
|
|
- v-if="
|
|
|
- !showScanningEffect &&
|
|
|
- selectedKeyElement &&
|
|
|
- elementOverlayStyle
|
|
|
- "
|
|
|
- ref="elementCardRef"
|
|
|
- class="element-overlay-card"
|
|
|
- :style="elementOverlayStyle"
|
|
|
- @click.stop
|
|
|
- >
|
|
|
- <div class="element-card-title">
|
|
|
- 当前选中:{{ selectedKeyElement }}
|
|
|
- </div>
|
|
|
- <ul
|
|
|
- v-if="filteredHazards.length"
|
|
|
- class="element-card-list"
|
|
|
- >
|
|
|
- <li
|
|
|
- v-for="(
|
|
|
- hazard, index
|
|
|
- ) in filteredHazards"
|
|
|
- :key="index"
|
|
|
- >
|
|
|
- {{ hazard }}
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
- <div v-else class="element-card-empty">
|
|
|
- 暂无对应隐患
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
<div
|
|
|
v-if="showScanningEffect"
|
|
|
class="scanning-overlay"
|
|
|
@@ -461,169 +431,61 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div class="analysis-section">
|
|
|
- <div class="analysis-header">
|
|
|
- <div class="robot-avatar">
|
|
|
- <img
|
|
|
- src="@/assets/Hazard/21.png"
|
|
|
- alt="蜀安AI助手"
|
|
|
- class="robot-img"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div class="header-title">
|
|
|
- <div
|
|
|
- v-if="showAnalysisPrompt"
|
|
|
- class="analysis-prompt"
|
|
|
- >
|
|
|
- <div class="typing-indicator">
|
|
|
- <span class="dot"></span>
|
|
|
- <span class="dot"></span>
|
|
|
- <span class="dot"></span>
|
|
|
- </div>
|
|
|
- <span class="prompt-text">蜀安AI助手正在为您智能分析图片,请稍候…</span>
|
|
|
- </div>
|
|
|
- <h3 v-else class="analysis-title">
|
|
|
- 蜀道安全管理AI智能助手慧眼识图分析出以下结果
|
|
|
- </h3>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <div class="analysis-body" v-if="!showAnalysisPrompt">
|
|
|
- <div class="analysis-text">
|
|
|
- <span
|
|
|
- v-if="isStreamingAnalysis"
|
|
|
- v-html="streamingAnalysis"
|
|
|
- class="streaming-text"
|
|
|
- ></span>
|
|
|
- <span
|
|
|
- v-else-if="
|
|
|
- !isStreamingAnalysis &&
|
|
|
- detectionResult
|
|
|
- "
|
|
|
- >
|
|
|
- 我识别到这是一个<span
|
|
|
- class="scene-tag"
|
|
|
- >{{
|
|
|
- detectionResult?.scene_name
|
|
|
- ? scenarios[
|
|
|
- detectionResult
|
|
|
- .scene_name
|
|
|
- ]?.name
|
|
|
- : "未知场景"
|
|
|
- }}</span
|
|
|
- >场景,检测到的关键要素为<span
|
|
|
- v-for="(label, index) in displayLabels"
|
|
|
- :key="index"
|
|
|
- class="label-tag"
|
|
|
- >{{ label }}</span
|
|
|
- >
|
|
|
- </span>
|
|
|
+ <!-- AI对话窗口占位 -->
|
|
|
+ <div class="ai-chat-placeholder">
|
|
|
+ <div class="chat-placeholder-content">
|
|
|
+ <div class="chat-icon">💬</div>
|
|
|
+ <div class="chat-text">AI对话功能即将上线</div>
|
|
|
+ <div class="chat-hint">敬请期待智能对话助手</div>
|
|
|
</div>
|
|
|
- <p
|
|
|
- class="hazards-intro"
|
|
|
- v-if="!isStreamingAnalysis && detectionResult"
|
|
|
- >
|
|
|
- 根据安全规范和施工标准,我为您梳理出以下需要重点关注的安全隐患
|
|
|
- </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <div
|
|
|
- v-if="
|
|
|
- !isStreamingAnalysis &&
|
|
|
- detectionResult &&
|
|
|
- keyElements.length
|
|
|
- "
|
|
|
- class="key-elements-section"
|
|
|
- >
|
|
|
- <div class="key-elements-title">关键要素</div>
|
|
|
- <div class="key-elements-buttons">
|
|
|
- <button
|
|
|
- v-for="element in keyElements"
|
|
|
- :key="element"
|
|
|
- :class="[
|
|
|
- 'key-element-btn',
|
|
|
- {
|
|
|
- active:
|
|
|
- selectedKeyElement ===
|
|
|
- element,
|
|
|
- },
|
|
|
- ]"
|
|
|
- @click="toggleKeyElement(element)"
|
|
|
- >
|
|
|
- {{ element }}
|
|
|
- </button>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- v-if="!selectedKeyElement"
|
|
|
- class="key-elements-hint"
|
|
|
- >
|
|
|
- 点击关键要素可查看对应隐患
|
|
|
- </div>
|
|
|
+ <!-- 右侧要素列表 -->
|
|
|
+ <div class="elements-sidebar">
|
|
|
+ <div class="sidebar-header">
|
|
|
+ <h3>检测要素</h3>
|
|
|
+ <span class="element-count">{{ keyElements.length }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="sidebar-content">
|
|
|
+ <div v-if="keyElements.length === 0" class="no-elements">
|
|
|
+ <div class="no-elements-icon">🔍</div>
|
|
|
+ <div class="no-elements-text">暂无检测要素</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <div
|
|
|
- class="hazards-section"
|
|
|
- v-if="!showAnalysisPrompt"
|
|
|
- >
|
|
|
+ <div v-else class="elements-list">
|
|
|
<div
|
|
|
- class="hazards-content"
|
|
|
- :class="{
|
|
|
- 'scanning-mode': showScanningEffect,
|
|
|
- }"
|
|
|
+ v-for="(element, index) in keyElements"
|
|
|
+ :key="index"
|
|
|
+ :class="['element-item', { 'element-active': selectedKeyElement === element, 'element-expanded': expandedElements[element] }]"
|
|
|
>
|
|
|
- <div
|
|
|
- v-if="showScanningEffect"
|
|
|
- class="hazards-loading-overlay"
|
|
|
- >
|
|
|
- <div class="loading-spinner"></div>
|
|
|
- <p>正在分析场景隐患...</p>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div
|
|
|
- v-else
|
|
|
- class="hazard-cards-container"
|
|
|
- >
|
|
|
- <div
|
|
|
- v-if="!filteredHazards.length"
|
|
|
- class="hazard-empty"
|
|
|
- >
|
|
|
- 暂无对应隐患
|
|
|
+ <div class="element-header" @click="toggleKeyElement(element)">
|
|
|
+ <div class="element-header-left">
|
|
|
+ <div class="element-number">{{ index + 1 }}</div>
|
|
|
+ <div class="element-name">{{ element }}</div>
|
|
|
</div>
|
|
|
- <div
|
|
|
- v-for="(
|
|
|
- hazard, index
|
|
|
- ) in filteredHazards"
|
|
|
- :key="index"
|
|
|
- class="hazard-card"
|
|
|
- :class="{
|
|
|
- show: visibleHazardCards[
|
|
|
- index
|
|
|
- ],
|
|
|
- }"
|
|
|
- >
|
|
|
- <div class="hazard-number">
|
|
|
- {{ index + 1 }}
|
|
|
+ <div class="element-header-right">
|
|
|
+ <div class="element-hazard-count">
|
|
|
+ {{ getElementHazards(element).length }} 项
|
|
|
</div>
|
|
|
- <div class="hazard-text-container">
|
|
|
- <p class="hazard-desc">
|
|
|
- {{ hazard }}
|
|
|
- </p>
|
|
|
- <a
|
|
|
- href="javascript:void(0);"
|
|
|
- class="example-link"
|
|
|
- @click.prevent="
|
|
|
- openExampleModal({
|
|
|
- number:
|
|
|
- index + 1,
|
|
|
- description:
|
|
|
- hazard,
|
|
|
- })
|
|
|
- "
|
|
|
- >
|
|
|
- 示例
|
|
|
- </a>
|
|
|
+ <div :class="['expand-arrow', { 'arrow-expanded': expandedElements[element] }]" @click.stop="toggleExpand(element)">
|
|
|
+ ▶
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div v-if="expandedElements[element]" class="element-hazards-list">
|
|
|
+ <div v-if="getElementHazards(element).length === 0" class="no-hazards-hint">暂无对应隐患</div>
|
|
|
+ <div
|
|
|
+ v-for="(hazard, hIdx) in getElementHazards(element)"
|
|
|
+ :key="hIdx"
|
|
|
+ class="hazard-detail-item"
|
|
|
+ @click.stop="openExampleModal({ number: hIdx + 1, description: hazard })"
|
|
|
+ >
|
|
|
+ <span class="hazard-detail-num">{{ hIdx + 1 }}</span>
|
|
|
+ <span class="hazard-detail-text">{{ hazard }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -1126,6 +988,8 @@ const isLoadingDetail = ref(false);
|
|
|
const isImageLoading = ref(false);
|
|
|
const isLoadingHistory = ref(false);
|
|
|
|
|
|
+const expandedElements = ref({});
|
|
|
+
|
|
|
const showEvaluationModal = ref(false);
|
|
|
const evaluationData = ref({
|
|
|
sceneMatch: null,
|
|
|
@@ -1309,6 +1173,20 @@ const selectedDetection = computed(() => {
|
|
|
);
|
|
|
});
|
|
|
|
|
|
+const getElementHazards = (element) => {
|
|
|
+ if (!detectionResult.value) return [];
|
|
|
+ const backendHazards = detectionResult.value?.element_hazards?.[element];
|
|
|
+ if (Array.isArray(backendHazards)) return backendHazards;
|
|
|
+ return hazardsMap.value[element] || [];
|
|
|
+};
|
|
|
+
|
|
|
+const toggleExpand = (element) => {
|
|
|
+ expandedElements.value = {
|
|
|
+ ...expandedElements.value,
|
|
|
+ [element]: !expandedElements.value[element],
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
const resetKeyElementState = () => {
|
|
|
selectedKeyElement.value = null;
|
|
|
elementOverlayStyle.value = null;
|
|
|
@@ -1320,6 +1198,8 @@ const toggleKeyElement = async (element) => {
|
|
|
} else {
|
|
|
selectedKeyElement.value = element;
|
|
|
}
|
|
|
+ // Toggle expand in sidebar
|
|
|
+ toggleExpand(element);
|
|
|
await nextTick();
|
|
|
updateElementOverlayPosition();
|
|
|
};
|
|
|
@@ -2603,7 +2483,14 @@ const getDetectionBoxStyle = (detection) => {
|
|
|
const handleDetectionBoxClick = (detection) => {
|
|
|
const label = normalizeLabel(detection?.label || '');
|
|
|
if (label) {
|
|
|
- toggleKeyElement(label);
|
|
|
+ // Select/deselect the element
|
|
|
+ if (selectedKeyElement.value === label) {
|
|
|
+ selectedKeyElement.value = null;
|
|
|
+ } else {
|
|
|
+ selectedKeyElement.value = label;
|
|
|
+ }
|
|
|
+ // Toggle expand in sidebar
|
|
|
+ toggleExpand(label);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -3323,9 +3210,9 @@ onBeforeUnmount(() => {
|
|
|
|
|
|
.detail-view .detail-content {
|
|
|
padding: 1rem;
|
|
|
- max-width: 56rem;
|
|
|
- width: 56rem;
|
|
|
- margin: 0 auto;
|
|
|
+ max-width: 100%;
|
|
|
+ width: 100%;
|
|
|
+ margin: 0;
|
|
|
position: relative;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
@@ -3394,7 +3281,8 @@ onBeforeUnmount(() => {
|
|
|
.detail-view .detail-content .image-section .image-container {
|
|
|
position: relative;
|
|
|
width: 100%;
|
|
|
- height: 350px;
|
|
|
+ height: calc(100vh - 380px);
|
|
|
+ min-height: 400px;
|
|
|
border-radius: 0.5rem;
|
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
border: 2px dashed #86efac;
|
|
|
@@ -4123,4 +4011,328 @@ body > .evaluation-modal-overlay {
|
|
|
padding: 0 !important;
|
|
|
box-sizing: border-box !important;
|
|
|
}
|
|
|
+
|
|
|
+/* 新布局样式 */
|
|
|
+.detail-content-wrapper {
|
|
|
+ display: flex;
|
|
|
+ gap: 20px;
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 0 24px 24px 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-main-area {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ min-width: 0;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-main-area .detail-content {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+ margin-bottom: 0;
|
|
|
+ -ms-overflow-style: none;
|
|
|
+ scrollbar-width: none;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-main-area .detail-content::-webkit-scrollbar {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+
|
|
|
+/* AI对话窗口占位 */
|
|
|
+.ai-chat-placeholder {
|
|
|
+ background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
|
|
|
+ border-radius: 12px;
|
|
|
+ border: 2px dashed #3b82f6;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: 100px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-top: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.chat-placeholder-content {
|
|
|
+ text-align: center;
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.chat-icon {
|
|
|
+ font-size: 48px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ animation: pulse 2s ease-in-out infinite;
|
|
|
+}
|
|
|
+
|
|
|
+.chat-text {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1e40af;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.chat-hint {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #64748b;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes pulse {
|
|
|
+ 0%, 100% {
|
|
|
+ transform: scale(1);
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ 50% {
|
|
|
+ transform: scale(1.1);
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 右侧要素列表 */
|
|
|
+.elements-sidebar {
|
|
|
+ width: 280px;
|
|
|
+ background: white;
|
|
|
+ border-radius: 12px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-header {
|
|
|
+ padding: 16px 20px;
|
|
|
+ border-bottom: 1px solid #e5e7eb;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ background: linear-gradient(135deg, #f8fafc 0%, #ffffff 100%);
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-header h3 {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.element-count {
|
|
|
+ background: #3b82f6;
|
|
|
+ color: white;
|
|
|
+ padding: 2px 8px;
|
|
|
+ border-radius: 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-content {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 12px;
|
|
|
+ -ms-overflow-style: none;
|
|
|
+ scrollbar-width: none;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-content::-webkit-scrollbar {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+
|
|
|
+.no-elements {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 40px 20px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.no-elements-icon {
|
|
|
+ font-size: 48px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ opacity: 0.5;
|
|
|
+}
|
|
|
+
|
|
|
+.no-elements-text {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #6b7280;
|
|
|
+}
|
|
|
+
|
|
|
+.elements-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.element-item {
|
|
|
+ background: #f9fafb;
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 12px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.element-item:hover {
|
|
|
+ background: #eff6ff;
|
|
|
+ border-color: #3b82f6;
|
|
|
+ transform: translateX(4px);
|
|
|
+}
|
|
|
+
|
|
|
+.element-item.element-active {
|
|
|
+ background: #dbeafe;
|
|
|
+ border-color: #3b82f6;
|
|
|
+ box-shadow: 0 2px 8px rgba(59, 130, 246, 0.2);
|
|
|
+}
|
|
|
+
|
|
|
+.element-number {
|
|
|
+ display: inline-block;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ background: #3b82f6;
|
|
|
+ color: white;
|
|
|
+ border-radius: 50%;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 20px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.element-active .element-number {
|
|
|
+ background: #1e40af;
|
|
|
+}
|
|
|
+
|
|
|
+.element-name {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.element-item {
|
|
|
+ padding: 0;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.element-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 12px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.element-header-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.element-header-right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.element-number {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.element-name {
|
|
|
+ margin-bottom: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.element-hazard-count {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #6b7280;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.element-active .element-hazard-count {
|
|
|
+ color: #3b82f6;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.expand-arrow {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #9ca3af;
|
|
|
+ transition: transform 0.3s ease;
|
|
|
+ cursor: pointer;
|
|
|
+ padding: 4px;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.expand-arrow:hover {
|
|
|
+ color: #3b82f6;
|
|
|
+ background: rgba(59, 130, 246, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.expand-arrow.arrow-expanded {
|
|
|
+ transform: rotate(90deg);
|
|
|
+ color: #3b82f6;
|
|
|
+}
|
|
|
+
|
|
|
+.element-hazards-list {
|
|
|
+ border-top: 1px solid #e5e7eb;
|
|
|
+ padding: 8px 12px;
|
|
|
+ background: #ffffff;
|
|
|
+}
|
|
|
+
|
|
|
+.no-hazards-hint {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #9ca3af;
|
|
|
+ text-align: center;
|
|
|
+ padding: 8px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.hazard-detail-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 6px 8px;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background 0.2s ease;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.hazard-detail-item:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.hazard-detail-item:hover {
|
|
|
+ background: #eff6ff;
|
|
|
+}
|
|
|
+
|
|
|
+.hazard-detail-num {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 18px;
|
|
|
+ height: 18px;
|
|
|
+ min-width: 18px;
|
|
|
+ background: #e5e7eb;
|
|
|
+ color: #6b7280;
|
|
|
+ border-radius: 50%;
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin-top: 2px;
|
|
|
+}
|
|
|
+
|
|
|
+.hazard-detail-text {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #374151;
|
|
|
+ line-height: 1.5;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.element-expanded {
|
|
|
+ border-color: #93c5fd;
|
|
|
+ background: #f0f9ff;
|
|
|
+}
|
|
|
</style>
|