|
|
@@ -0,0 +1,520 @@
|
|
|
+<template>
|
|
|
+ <div class="tips-report-container">
|
|
|
+ <div class="left-sidebar">
|
|
|
+ <div class="sidebar-header">
|
|
|
+ <h3>历史记录</h3>
|
|
|
+ <button class="new-task-btn">+ 新建任务</button>
|
|
|
+ </div>
|
|
|
+ <div class="task-list">
|
|
|
+ <div
|
|
|
+ v-for="task in taskList"
|
|
|
+ :key="task.id"
|
|
|
+ :class="['task-item', { active: currentTaskId === task.id }]"
|
|
|
+ @click="selectTask(task)"
|
|
|
+ >
|
|
|
+ <div class="task-image">
|
|
|
+ <img :src="task.image" alt="任务图片" />
|
|
|
+ </div>
|
|
|
+ <div class="task-info">
|
|
|
+ <span class="task-title">{{ task.title }}</span>
|
|
|
+ <span class="task-time">{{ task.time }}</span>
|
|
|
+ </div>
|
|
|
+ <span :class="['task-status', task.status]">{{ task.statusText }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="main-content">
|
|
|
+ <div class="content-header">
|
|
|
+ <h2>隐患提示</h2>
|
|
|
+ <div class="header-right">
|
|
|
+ <button class="btn-add-tag">+ 添加站</button>
|
|
|
+ <span class="current-time">6月12日 15:52</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="content-body">
|
|
|
+ <div class="center-panel">
|
|
|
+ <div class="image-section">
|
|
|
+ <img :src="currentTask.image" alt="现场图片" class="main-image" />
|
|
|
+ <div class="image-nav">
|
|
|
+ <span class="nav-info">1 / 6</span>
|
|
|
+ </div>
|
|
|
+ <!-- 标注框 -->
|
|
|
+ <div
|
|
|
+ v-for="(tag, index) in currentTask.tags"
|
|
|
+ :key="index"
|
|
|
+ :style="{ top: tag.top, left: tag.left }"
|
|
|
+ class="tag-box"
|
|
|
+ @click="selectTag(tag)"
|
|
|
+ >
|
|
|
+ {{ tag.label }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="ai-section">
|
|
|
+ <div class="section-header">
|
|
|
+ <span class="section-title">隐患提示说明</span>
|
|
|
+ <!-- <span class="ai-badge">AI安全提醒</span> -->
|
|
|
+ </div>
|
|
|
+ <div class="ai-content">
|
|
|
+ <p>{{ currentTask.aiWarning }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="right-panel">
|
|
|
+ <div class="panel-section">
|
|
|
+ <div class="section-header">
|
|
|
+ <span class="section-title">建议整改清单</span>
|
|
|
+ </div>
|
|
|
+ <div class="checklist">
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in currentTask.checklist"
|
|
|
+ :key="index"
|
|
|
+ :class="['checklist-item', { checked: item.checked }]"
|
|
|
+ >
|
|
|
+ <input type="checkbox" :checked="item.checked" @change="toggleCheck(index)" />
|
|
|
+ <span>{{ item.text }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed } from 'vue'
|
|
|
+
|
|
|
+const taskList = ref([
|
|
|
+ {
|
|
|
+ id: 1,
|
|
|
+ title: '加油站',
|
|
|
+ time: '6月12日 17:12',
|
|
|
+ status: 'completed',
|
|
|
+ statusText: '已完成',
|
|
|
+ image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=gas%20station%20outdoor%20view&image_size=landscape_4_3',
|
|
|
+ aiWarning: '综合安全风险提示:图中出现加油机、加油枪、防撞柱、加油机输油管、配电箱、灭火器等关键设备设施。经AI图像智能分析,识别出以下安全隐患风险点:加油机周边地面存在疑似油污痕迹,需及时清理以防人员滑倒;配电箱外部存在轻微破损,建议检查内部线路防护状况;消防灭火器放置位置虽符合规范,但需确认压力值是否在正常范围;防撞柱反光标识存在局部褪色,建议定期更换以保障夜间警示效果。综合评估当前场景整体安全状况为中等风险,建议立即安排专业人员对上述隐患点进行逐一排查整改,确保加油站运营安全。',
|
|
|
+ tags: [
|
|
|
+ { label: '加油机', top: '55%', left: '32%' },
|
|
|
+ { label: '加油机', top: '55%', left: '45%' },
|
|
|
+ { label: '加油机', top: '55%', left: '52%' },
|
|
|
+ { label: '防撞柱', top: '75%', left: '28%' },
|
|
|
+ { label: '防撞柱', top: '75%', left: '62%' },
|
|
|
+ { label: '防撞柱', top: '75%', left: '68%' },
|
|
|
+ { label: '配电箱', top: '45%', left: '18%' },
|
|
|
+ ],
|
|
|
+ checklist: [
|
|
|
+ { text: '请检查外观是否整洁,是否存在油污堆积;检查外观是否整洁,是否存在油污堆积;检查外观是否整洁,是否存在油污堆积', checked: false },
|
|
|
+ { text: '请确认加油机输油管及阀门连接是否牢固,定期进行紧固检查,以防泄漏或松动;检查外观是否整洁,是否存在油污堆积', checked: false },
|
|
|
+ { text: '请检查灭火器是否在有效期内,压力是否正常,放置位置是否便于取用;检查外观是否整洁,是否存在油污堆积', checked: false },
|
|
|
+ { text: '请检查配电箱及线路是否规范,是否存在私拉乱接;检查外观是否整洁,是否存在油污堆积', checked: false },
|
|
|
+ { text: '请检查防撞柱是否完好,高度是否符合要求,表面反光标识是否清晰;检查外观是否整洁,是否存在油污堆积', checked: false },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 2,
|
|
|
+ title: '隧道工程',
|
|
|
+ time: '6月12日 15:53',
|
|
|
+ status: 'processing',
|
|
|
+ statusText: '处理中',
|
|
|
+ image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=tunnel%20construction%20site&image_size=landscape_4_3',
|
|
|
+ aiWarning: '隧道施工风险提示:检测到隧道内存在施工设备、临时支护结构等,建议关注支护稳定性、通风系统运行状态及照明设施完好情况。',
|
|
|
+ tags: [],
|
|
|
+ checklist: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 3,
|
|
|
+ title: '加油站',
|
|
|
+ time: '6月12日 15:52',
|
|
|
+ status: 'processing',
|
|
|
+ statusText: '处理中',
|
|
|
+ image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=gas%20station%20outdoor%20view%202&image_size=landscape_4_3',
|
|
|
+ aiWarning: '综合安全风险提示:检测到多个加油机位、消防设施及电气设备,建议全面检查设备运行状态及安全防护措施。',
|
|
|
+ tags: [],
|
|
|
+ checklist: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 4,
|
|
|
+ title: '加油站',
|
|
|
+ time: '6月12日 15:49',
|
|
|
+ status: 'pending',
|
|
|
+ statusText: '待处理',
|
|
|
+ image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=gas%20station%20equipment&image_size=landscape_4_3',
|
|
|
+ aiWarning: '',
|
|
|
+ tags: [],
|
|
|
+ checklist: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 5,
|
|
|
+ title: '加油站',
|
|
|
+ time: '6月12日 15:48',
|
|
|
+ status: 'pending',
|
|
|
+ statusText: '待处理',
|
|
|
+ image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=gas%20station%20fuel%20dispenser&image_size=landscape_4_3',
|
|
|
+ aiWarning: '',
|
|
|
+ tags: [],
|
|
|
+ checklist: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 6,
|
|
|
+ title: '桥梁工程',
|
|
|
+ time: '6月12日 15:48',
|
|
|
+ status: 'pending',
|
|
|
+ statusText: '待处理',
|
|
|
+ image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=bridge%20construction%20site&image_size=landscape_4_3',
|
|
|
+ aiWarning: '',
|
|
|
+ tags: [],
|
|
|
+ checklist: []
|
|
|
+ },
|
|
|
+])
|
|
|
+
|
|
|
+const currentTaskId = ref(1)
|
|
|
+
|
|
|
+const currentTask = computed(() => {
|
|
|
+ return taskList.value.find(t => t.id === currentTaskId.value) || taskList.value[0]
|
|
|
+})
|
|
|
+
|
|
|
+const selectTask = (task) => {
|
|
|
+ currentTaskId.value = task.id
|
|
|
+}
|
|
|
+
|
|
|
+const selectTag = (tag) => {
|
|
|
+ console.log('Selected tag:', tag)
|
|
|
+}
|
|
|
+
|
|
|
+const toggleCheck = (index) => {
|
|
|
+ if (currentTask.value.checklist[index]) {
|
|
|
+ currentTask.value.checklist[index].checked = !currentTask.value.checklist[index].checked
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.tips-report-container {
|
|
|
+ display: flex;
|
|
|
+ height: 100%;
|
|
|
+ background: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.left-sidebar {
|
|
|
+ width: 280px;
|
|
|
+ background: #fff;
|
|
|
+ border-right: 1px solid #e8e8e8;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 16px 20px;
|
|
|
+ border-bottom: 1px solid #e8e8e8;
|
|
|
+
|
|
|
+ h3 {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .new-task-btn {
|
|
|
+ padding: 6px 16px;
|
|
|
+ background: #1890ff;
|
|
|
+ color: #fff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 13px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.task-list {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.task-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 12px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ border-radius: 8px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s;
|
|
|
+ border: 1px solid transparent;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #f5f7fa;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ background: #e6f7ff;
|
|
|
+ border-color: #1890ff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-image {
|
|
|
+ width: 50px;
|
|
|
+ height: 50px;
|
|
|
+ border-radius: 6px;
|
|
|
+ overflow: hidden;
|
|
|
+ margin-right: 12px;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-info {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+
|
|
|
+ .task-title {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-time {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-status {
|
|
|
+ padding: 2px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+
|
|
|
+ &.completed {
|
|
|
+ background: #f6ffed;
|
|
|
+ color: #52c41a;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.processing {
|
|
|
+ background: #fffbe6;
|
|
|
+ color: #faad14;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.pending {
|
|
|
+ background: #f5f5f5;
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.main-content {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding: 20px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.content-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ h2 {
|
|
|
+ font-size: 20px;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header-right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16px;
|
|
|
+
|
|
|
+ .btn-add-tag {
|
|
|
+ padding: 6px 16px;
|
|
|
+ background: #1890ff;
|
|
|
+ color: #fff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 13px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .current-time {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.content-body {
|
|
|
+ display: flex;
|
|
|
+ gap: 20px;
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.center-panel {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 20px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.image-section {
|
|
|
+ position: relative;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: 0 1px 4px rgba(0,0,0,0.05);
|
|
|
+ height: calc(100vh * 5 / 7);
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ .main-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+
|
|
|
+ .image-nav {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 16px;
|
|
|
+ right: 16px;
|
|
|
+ padding: 4px 12px;
|
|
|
+ background: rgba(0,0,0,0.6);
|
|
|
+ color: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+
|
|
|
+ .nav-info {
|
|
|
+ margin-right: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .tag-box {
|
|
|
+ position: absolute;
|
|
|
+ padding: 4px 10px;
|
|
|
+ background: #1890ff;
|
|
|
+ color: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ cursor: pointer;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #40a9ff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.ai-section {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 16px;
|
|
|
+ box-shadow: 0 1px 4px rgba(0,0,0,0.05);
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ .section-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+
|
|
|
+ .section-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ai-badge {
|
|
|
+ padding: 2px 8px;
|
|
|
+ background: #f6ffed;
|
|
|
+ color: #52c41a;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .ai-content {
|
|
|
+ background: #f6ffed;
|
|
|
+ padding: 12px 16px;
|
|
|
+ border-radius: 8px;
|
|
|
+
|
|
|
+ p {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666;
|
|
|
+ line-height: 1.6;
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.right-panel {
|
|
|
+ width: 360px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.panel-section {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 16px;
|
|
|
+ box-shadow: 0 1px 4px rgba(0,0,0,0.05);
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .section-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ .section-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .checklist {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ .checklist-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ padding: 10px 0;
|
|
|
+ border-bottom: 1px solid #f5f5f5;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ input {
|
|
|
+ margin-right: 12px;
|
|
|
+ margin-top: 2px;
|
|
|
+ cursor: pointer;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ span {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #666;
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.checked span {
|
|
|
+ text-decoration: line-through;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|