<template>
|
<div>
|
<!-- 新增实时监控弹窗 -->
|
<el-dialog title="实时监控" :visible.sync="realTimeVisible" width="60%" custom-class="resizable-dialog" :modal="true"
|
:lock-scroll="false" :close-on-click-modal="false">
|
<!-- <div class="dialog-content"> -->
|
<camera-video @close="realTimeVisible = false" />
|
<!-- <p>尝试拖拽边缘或角落调整大小</p>
|
<div v-for="handle in handles" :key="handle.position" class="resize-handle" :class="handle.position"
|
@mousedown.prevent="startResize(handle.position, $event)">
|
</div>
|
</div> -->
|
</el-dialog>
|
<!-- 详情弹窗 -->
|
<!-- 修改后的详情弹窗 -->
|
<el-dialog :visible.sync="detailVisible" title="" width="660px" custom-class="detail-dialog right-aligned">
|
<!-- 顶部切换按钮 -->
|
<div class="media-switch">
|
<el-radio-group v-model="currentMediaType">
|
<el-radio-button label="image" class="media-tab">大图</el-radio-button>
|
<el-radio-button label="video" class="media-tab">视频</el-radio-button>
|
</el-radio-group>
|
</div>
|
<el-divider></el-divider>
|
<!-- 上部媒体区 -->
|
<div class="media-container">
|
<div v-if="currentMediaType === 'image'" class="main-image">
|
<el-image :src="detailItem.image_path" alt="事件截图" class="detail-img previewable-image"
|
:preview-src-list="[detailItem.image_path]" />
|
</div>
|
<div v-else class="video-section">
|
<div class="video-placeholder">
|
<!-- 修改video标签部分 -->
|
<video :src="detailItem.video_path" controls style="width: 100%; height: 100%; object-fit: contain"></video>
|
<!-- <wasm-player style="width: 100%; height: 100%; object-fit: contain"></wasm-player> -->
|
</div>
|
</div>
|
</div>
|
|
<!-- 下部信息区 -->
|
<div class="info-container">
|
<!-- <el-descriptions :column="2" border> -->
|
<el-descriptions :column="1">
|
<el-descriptions-item label="时间" class="info-item">
|
<span style="width: 28px"></span>
|
<span class="info-value">{{
|
formatStartDateTime(detailItem.detect_time)
|
}}</span>
|
</el-descriptions-item>
|
|
<el-descriptions-item label="视频点位" class="info-item">
|
<span class="info-value">{{ detailItem.video_name }}</span>
|
</el-descriptions-item>
|
<el-descriptions-item label="任务名称" v-if="backendData">
|
<span class="multi-value">
|
{{ detailItem.task_names }}
|
</span>
|
</el-descriptions-item>
|
|
<el-descriptions-item label="事件等级" v-if="backendData">
|
<span style="background-color: #f70713; width: 25px; height: 15px">
|
</span><span style="width: 5px"></span>{{ detailItem.event_levels }}
|
</el-descriptions-item>
|
|
<el-descriptions-item label="隐患描述" v-if="backendData">
|
<el-tooltip placement="top" :content="detailItem.risk_description" effect="light"
|
popper-class="my-tooltip">
|
<span class="multi-value ellipsis">{{ detailItem.risk_description }}</span>
|
</el-tooltip>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="处理建议" v-if="backendData">
|
<el-tooltip placement="top" :content="detailItem.suggestion" effect="light" popper-class="my-tooltip">
|
<span class="multi-value ellipsis">{{ detailItem.suggestion }}</span>
|
</el-tooltip>
|
</el-descriptions-item>
|
<el-descriptions-item label="相关文档" v-if="backendData">
|
<div v-for="(doc, index) in detailItem.knowledge_documents || []" :key="index" class="multi-value">
|
<!-- <a :href="getPreviewUrl(doc)" target="_blank" class="doc-link" style="text-decoration: none;">
|
<span>《{{ doc.fileName }}》</span>
|
</a> -->
|
<span class="doc-link" @click="getPreviewUrl2(doc.id)">《{{ doc.fileName }}》</span>
|
<span v-if="index < detailItem.knowledge_documents.length - 1">, </span>
|
</div>
|
</el-descriptions-item>
|
<el-descriptions-item label="图片内容" style="">
|
<div class="desc_class">
|
<span class="multi-value2">
|
{{ detailItem.zh_desc_class }}
|
</span>
|
</div>
|
</el-descriptions-item>
|
|
</el-descriptions>
|
</div>
|
</el-dialog>
|
|
<div class="statistics-container">
|
<!-- 左侧筛选栏 -->
|
<div class="left-sidebar" :class="{ collapsed: isSidebarCollapsed }">
|
<div class="stats-header">
|
<div class="ai-avatar">
|
<img :src="require('@/assets/img/AI-avatar.png')" class="avatar-img" />
|
<div class="header-text" v-show="!isSidebarCollapsed">
|
<h3 class="content-title header-gradient2">你好,我是小贝</h3>
|
<div class="stats-numbers">
|
<span>很高兴见到你!</span>
|
</div>
|
</div>
|
<div class="header-actions">
|
<img :src="require('@/assets/img/fold_up.png')" class="fold-icon" :class="{ reverse: isSidebarCollapsed }"
|
@click="toggleSidebar" />
|
<img v-if="isSidebarCollapsed" :src="require('@/assets/img/conversation.png')" class="fold-icon"
|
:class="{ reverse: isSidebarCollapsed }" @click="handleNewSession" />
|
<img v-if="isSidebarCollapsed" :src="require('@/assets/img/historical.png')" class="fold-icon"
|
:class="{ reverse: isSidebarCollapsed }" @click="handleHistoryClick" />
|
</div>
|
</div>
|
</div>
|
<div class="session-buttons" v-if="!isSidebarCollapsed">
|
<el-button @click="handleHistoryClick" type="primary" round class="history-btn"
|
style="flex: 1; margin-right: 10px">
|
历史会话
|
</el-button>
|
<el-button @click="handleNewSession" type="primary" round class="new-session-btn"
|
style="flex: 1; position: relative">
|
开启新会话
|
<i class="el-icon-arrow-right" style="margin-left: 8px; font-size: 14px"></i>
|
</el-button>
|
</div>
|
<el-divider v-if="!isSidebarCollapsed"></el-divider>
|
<!-- AI检索组件 -->
|
<ai-retrieval @list-selected="handleAiRetrievalSelected" :current-chat-id="selectedChatId" ref="aiRetrieval"
|
class="ai-retrieval-container" v-show="showAIRetrieval && !isSidebarCollapsed" />
|
<chat-history @item-selected="handleHistorySelected" class="ai-retrieval-container"
|
v-show="!showAIRetrieval && !isSidebarCollapsed" />
|
</div>
|
|
<!-- 右侧主内容 -->
|
<div class="right-content">
|
<div class="right-header">
|
<h2 class="content-title" >
|
<span class="header-gradient">AI</span><span style="margin-left: 15px;font-size: 30px">文搜万物</span>
|
</h2>
|
<div class="header-actions-right">
|
<el-button type="primary" class="action-btn" @click="handleRealTimeMonitor">
|
实时监控
|
</el-button>
|
<el-button type="primary" class="action-btn" @click="resetList()">
|
刷新数据
|
</el-button>
|
</div>
|
</div>
|
<!-- 检测结果展示 -->
|
<div class="content-wrapper">
|
<!-- 添加数据加载状态提示 -->
|
<div v-if="isLoading" class="loading-container">
|
<el-icon class="is-loading" size="24">
|
<Loading />
|
</el-icon>
|
<span>数据加载中...</span>
|
</div>
|
<!-- 无限滚动容器 -->
|
<div class="results-container" @scroll="handleScroll">
|
<el-empty v-if="results.length === 0" description="暂无数据" style="margin-top: 50px"></el-empty>
|
<div v-else class="gallery-section">
|
<div class="image-grid-container">
|
<div class="image-grid" ref="imageGrid">
|
<div v-for="(item, index) in results" :key="index" class="image-card-wrapper"
|
:style="{ width: cardWidth }">
|
<el-card class="result-card" :class="{ 'selected-card': selectedItemId === item.id }"
|
@click.native.stop="handleCardClick(item)">
|
<div class="image-wrapper">
|
<el-image slot="error" :src="item.image_path" class="result-image" alt="检测结果" />
|
<!-- <img slot="error" src="@/assets/01.png" class="result-image" alt="检测结果" /> -->
|
<div class="image-overlay" v-if="item.is_warning == 1">
|
<span class="check-item">
|
{{ item.task_names }}
|
</span>
|
<el-tag size="mini" class="level-tag">
|
{{ item.event_levels }}
|
</el-tag>
|
</div>
|
</div>
|
<div class="card-content">
|
<div class="meta-info">
|
<div class="time-info">
|
<img src="@/assets/img/time-fill@1x.png" alt="" class="time-icon">
|
<span class="detect-time">{{ formatStartDateTime(item.detect_time) }}</span>
|
<el-popover placement="bottom" width="300" trigger="click" v-model="popoverVisible[index]"
|
v-if="item.is_desc === 2" class="right-btn2">
|
<i class="el-icon-close" @click="closePopover(index)"></i>
|
<span style="color: black; font-weight: 600">图片内容</span>
|
<div class="task-popover-content">
|
{{ item.zh_desc_class }}
|
</div>
|
<img src="@/assets/img/article-fill@1x.png" alt="" class="time-icon2" slot="reference"
|
@click.stop="togglePopover(index)">
|
</el-popover>
|
</div>
|
<div class="device-info">
|
<div class="camera-info">
|
<img src="@/assets/img/live-fill@1x.png" alt="" class="time-icon">
|
<span>{{ item.video_name }}</span>
|
<el-dropdown size="small" @command="handleCommand" class="right-btn">
|
<img src="@/assets/img/modelTraining.png"
|
style="width: 16px;height: 16px;margin-left: 10px; vertical-align: middle">
|
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-item
|
:command="{ ruleName: item.rule_names ? item.rule_names[0].fileName : '', cameraId: item.video_point_id + '', cameraName: item.video_name, imagePath: item.image_path, status: 1 }">正确</el-dropdown-item>
|
<el-dropdown-item
|
:command="{ ruleName: item.rule_names ? item.rule_names[0].fileName : '', cameraId: item.video_point_id + '', cameraName: item.video_name, imagePath: item.image_path, status: 2 }">错误</el-dropdown-item>
|
<el-dropdown-item
|
:command="{ ruleName: item.rule_names ? item.rule_names[0].fileName : '', cameraId: item.video_point_id + '', cameraName: item.video_name, imagePath: item.image_path, status: 0 }">不确定</el-dropdown-item>
|
</el-dropdown-menu>
|
</el-dropdown>
|
</div>
|
</div>
|
</div>
|
</div>
|
</el-card>
|
</div>
|
</div>
|
</div>
|
</div>
|
<!-- 滚动加载提示 -->
|
<div v-if="isLoadingMore" class="loading-more">
|
<el-icon class="is-loading" size="16">
|
<Loading />
|
</el-icon>
|
<span>加载更多...</span>
|
</div>
|
<div v-if="!hasMore && results.length > 0" class="no-more-data">
|
没有更多数据了
|
</div>
|
|
</div>
|
|
<!-- 分页 -->
|
<!-- <div class="pagination-wrapper" v-if="results.length > 0">
|
<el-pagination :current-page="currentPage" :page-size="16" :total="totalResults"
|
layout="prev, pager, next" @current-change="handlePageChange">
|
</el-pagination>
|
</div> -->
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import _ from 'lodash'; // 用于防抖
|
import surey from "@/api/SurveyView";
|
import aiRetrieval from './AiRetrievalView';
|
import chatHistory from './ChatHistoryView';
|
import cameraVideo from './cameraVideo.vue';
|
export default {
|
components: {
|
aiRetrieval,
|
chatHistory,
|
cameraVideo
|
},
|
data() {
|
return {
|
// 新增卡片宽度计算相关数据
|
cardWidth: '300px', // 默认卡片宽度
|
minCardWidth: 300, // 卡片最小宽度
|
margin: 20, // 卡片间距
|
idsList: [],
|
pageSize: 30, // 每页加载数据量
|
hasMore: true, // 是否有更多数据
|
isLoadingMore: false, // 是否正在加载更多
|
scrollTop: 0, // 滚动位置记录
|
docUrl: "",
|
isLoading: false, // 新增加载状态变量
|
backendData: true,
|
popoverVisible: {}, // 用于控制每个卡片的气泡显示状态
|
dialogVisible: true,
|
handles: [
|
{ position: "top" },
|
{ position: "bottom" },
|
{ position: "left" },
|
{ position: "right" },
|
{ position: "top-left" },
|
{ position: "top-right" },
|
{ position: "bottom-left" },
|
{ position: "bottom-right" },
|
],
|
isResizing: false,
|
startX: 0,
|
startY: 0,
|
startWidth: 0,
|
startHeight: 0,
|
startLeft: 0,
|
startTop: 0,
|
realTimeVisible: false, // 新增弹窗控制变量
|
selectedChatId: null,
|
showAIRetrieval: true,
|
isSidebarCollapsed: false,
|
selectedItemId: null, // 新增选中项ID
|
filterOptions: {
|
tasks: [],
|
levels: [],
|
cameras: [],
|
rules: [],
|
},
|
currentMediaType: "image", // 当前媒体类型
|
detailVisible: false,
|
detailItem: {},
|
currentPage: 1,
|
totalResults: 40, // 总数据量
|
filter: {
|
keyword: "",
|
task: "",
|
timeRange: [],
|
level: "",
|
camera: "",
|
rules: "",
|
},
|
showWarningOnly: true,
|
results: [
|
{
|
// image_path: require("@/assets/01.png"),
|
// video_path: require("@/assets/video.mp4"),
|
risk_description: "隐患描述",
|
detect_time: "2021-12-09 20:23",
|
video_name: "摄像机A",
|
event_level: "1",
|
is_warning: 1,
|
event_levels: "一级",
|
task_names: "生产任务管控,生产任务管控,生产任务管控,生产任务管控,生产任务管控", // 改为数组
|
suggestion: "处理建议", // 处理建议
|
video_point_id: 1,
|
rule_names: "",
|
knowledge_documents: [
|
{ ruleId: 1, fileName: "安全准则", file_url: "https://image.baidu.com/search/detail?z=0&word=%E5%9B%BE%E7%89%87&hs=0&pn=1&spn=0&di=7498023338351001601&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&ie=utf-8&oe=utf-8&lm=&cs=2629589424%2C2655723787&os=2900564191%2C785059641&simid=3974997321%2C325136453&adpicid=0&lpn=0&fr=click-pic&fm=&ic=&hd=&latest=©right=&isImgSet=&commodity=&hot=&imgratio=&imgformat=&sme=&width=0&height=0&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fww2.sinaimg.cn%2Fmw690%2F61d7678dgy1hvt194v9kqj20p00uuape.jpg&fromurl=ippr_z2C%24qAzdH3FAzdH3Fojtk5_z%26e3Bv54AzdH3F8m98cam0a8AzdH3FP81pPuN3N&gsm=1e&islist=&querylist=&lid=9dec68e500008991" },
|
{ ruleId: 1, fileName: "安全准则", file_url: "http://192.168.1.232:7010/home/debian/GroundingDINO/txt/zs/AI-avatar.png" },
|
], // 预警规则数组
|
zh_desc_class: "图片显示的是一个室内场景,时间戳显示为2025年6月27日星期五16:57:12。画面中可以看到一个走廊过道的环境,右侧有一扇玻璃门,门上覆盖着蓝色的防尘布。左侧墙上有一个黑板,上面写有一些中文和英文的文字,内容包括“莫伟达”、“int4”、“AWQ”、“4G”等。黑板旁边有一个白色的柜子,柜子上放着一些物品。墙角处还有一株小树。整个房间的墙壁是白色的,天花板也是白色的图片显示的是一个室内场景,时间戳显示为2025年6月27日星期五16:57:12。画面中可以看到一个走廊过道的环境,右侧有一扇玻璃门,门上覆盖着蓝色的防尘布。左侧墙上有一个黑板,上面写有一些中文和英文的文字,内容包括“莫伟达”、“int4”、“AWQ”、“4G”等。黑板旁边有一个白色的柜子,柜子上放着一些物品。墙角处还有一株小树。整个房间的墙壁是白色的,天花板也是白色的"
|
},
|
{
|
image_path: "",
|
risk_description: "隐患描述",
|
detect_time: "2021-12-09 21:15",
|
video_name: "摄像机B",
|
is_desc: 2,
|
zh_desc_class: "图片显示的是一个室内场景,时间戳显示为2025年6月27日星期五16:57:12。画面中可以看到一个走廊过道的环境,右侧有一扇玻璃门,门上覆盖着蓝色的防尘布。左侧墙上有一个黑板,上面写有一些中文和英文的文字,内容包括“莫伟达”、“int4”、“AWQ”、“4G”等。黑板旁边有一个白色的柜子,柜子上放着一些物品。墙角处还有一株小树。整个房间的墙壁是白色的,天花板也是白色的图片显示的是一个室内场景,时间戳显示为2025年6月27日星期五16:57:12。画面中可以看到一个走廊过道的环境,右侧有一扇玻璃门,门上覆盖着蓝色的防尘布。左侧墙上有一个黑板,上面写有一些中文和英文的文字,内容包括“莫伟达”、“int4”、“AWQ”、“4G”等。黑板旁边有一个白色的柜子,柜子上放着一些物品。墙角处还有一株小树。整个房间的墙壁是白色的,天花板也是白色的图片显示的是一个室内场景,时间戳显示为2025年6月27日星期五16:57:12。画面中可以看到一个走廊过道的环境,右侧有一扇玻璃门,门上覆盖着蓝色的防尘布。左侧墙上有一个黑板,上面写有一些中文和英文的文字,内容包括“莫伟达”、“int4”、“AWQ”、“4G”等。黑板旁边有一个白色的柜子,柜子上放着一些物品。墙角处还有一株小树。整个房间的墙壁是白色的,天花板也是白色的图片显示的是一个室内场景,时间戳显示为2025年6月27日星期五16:57:12。画面中可以看到一个走廊过道的环境,右侧有一扇玻璃门,门上覆盖着蓝色的防尘布。左侧墙上有一个黑板,上面写有一些中文和英文的文字,内容包括“莫伟达”、“int4”、“AWQ”、“4G”等。黑板旁边有一个白色的柜子,柜子上放着一些物品。墙角处还有一株小树。整个房间的墙壁是白色的,天花板也是白色的图片显示的是一个室内场景,时间戳显示为2025年6月27日星期五16:57:12。画面中可以看到一个走廊过道的环境,右侧有一扇玻璃门,门上覆盖着蓝色的防尘布。左侧墙上有一个黑板,上面写有一些中文和英文的文字,内容包括“莫伟达”、“int4”、“AWQ”、“4G”等。黑板旁边有一个白色的柜子,柜子上放着一些物品。墙角处还有一株小树。整个房间的墙壁是白色的,天花板也是白色的图片显示的是一个室内场景,时间戳显示为2025年6月27日星期五16:57:12。画面中可以看到一个走廊过道的环境,右侧有一扇玻璃门,门上覆盖着蓝色的防尘布。左侧墙上有一个黑板,上面写有一些中文和英文的文字,内容包括“莫伟达”、“int4”、“AWQ”、“4G”等。黑板旁边有一个白色的柜子,柜子上放着一些物品。墙角处还有一株小树。整个房间的墙壁是白色的,天花板也是白色的"
|
},
|
],
|
};
|
},
|
computed: {
|
normalizedPath() {
|
return (backendPath) => {
|
// 替换逻辑
|
return require(backendPath
|
.replace(/^[a-zA-Z]:/, "") // 去除盘符
|
.replace(/\/+/g, "/") // 合并多余斜杠
|
.replace("/opt/smart", "@/assets")); // 关键路径替换
|
};
|
},
|
visibleResults() {
|
return this.results.slice(
|
(this.currentPage - 1) * 8,
|
this.currentPage * 8
|
);
|
},
|
boxHeight() {
|
// 根据后端数据决定高度
|
// if (!this.backendData) return "380px";
|
return this.backendData ? "160px" : "320px";
|
},
|
},
|
mounted() {
|
// this.fetchFilterOptions();//筛选列表
|
this.handleSearch([]);
|
this.fetchCameraInfo();
|
this.resetList();
|
this.calculateCardWidth();
|
// 添加防抖的resize监听
|
window.addEventListener('resize', _.debounce(this.calculateCardWidth, 100));
|
},
|
beforeDestroy() {
|
window.removeEventListener('resize', this.calculateCardWidth);
|
},
|
methods: {
|
// 新增卡片宽度计算方法
|
calculateCardWidth() {
|
if (this.$refs.imageGrid) {
|
const containerWidth = this.$refs.imageGrid.clientWidth;
|
// 计算每行可以放置的卡片数量,最少3列
|
const cardsPerRow = Math.max(3, Math.floor(containerWidth / (this.minCardWidth + this.margin)));
|
|
// 设置卡片宽度公式
|
this.cardWidth = `calc(${100 / cardsPerRow}% - ${this.margin}px)`;
|
}
|
},
|
handleCommand(command) {
|
console.log(JSON.stringify(command))
|
surey.insertModelTraining(JSON.stringify(command)).then((res) => {
|
if (res && res.status === 200) {
|
this.$notify({
|
type: "success",
|
message: "添加成功",
|
});
|
} else {
|
this.$notify({
|
type: "error",
|
message: "添加失败!",
|
});
|
}
|
});
|
},
|
// 重置列表
|
resetList() {
|
this.idsList = [];
|
this.currentPage = 1;
|
this.hasMore = true;
|
this.results = [];
|
this.handleSearch([]);
|
},
|
|
// 滚动事件处理
|
handleScroll(event) {
|
const container = event.target;
|
// 记录滚动位置
|
this.scrollTop = container.scrollTop;
|
|
// 检查是否滚动到底部
|
const isBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 50;
|
|
// 当滚动到底部且有更多数据,且当前没有加载中,则加载更多
|
if (isBottom && this.hasMore && !this.isLoading && !this.isLoadingMore) {
|
this.loadMoreData();
|
}
|
},
|
// 加载更多数据
|
async loadMoreData() {
|
if (this.isLoadingMore || !this.hasMore) return;
|
|
try {
|
this.isLoadingMore = true;
|
this.currentPage++;
|
|
const params = {
|
ids: [],
|
page: this.currentPage,
|
pageSize: this.pageSize
|
};
|
|
const response = await surey.getSurveys(params);
|
const lists = response.data.list || [];
|
if (lists) {
|
for (let i = 0; i < lists.length; i++) {
|
console.log("333:" + lists[i].video_point_id)
|
this.results.push({
|
task_names: lists[i].task_name,
|
video_name: lists[i].video_name,
|
image_path: "/api-img" + lists[i].image_path,
|
video_path: "/api-img" + lists[i].video_path,
|
detect_time: lists[i].detect_time,
|
event_levels: lists[i].event_level_name,
|
zh_desc_class: lists[i].zh_desc_class,
|
is_warning: lists[i].is_warning,
|
is_desc: lists[i].is_desc,
|
video_point_id: lists[i].video_point_id,
|
rule_names: lists[i].rule_names,
|
knowledge_documents: lists[i].knowledge_documents.map(file => {
|
return {
|
...file,
|
file_url: "/api-img" + file.file_url,
|
fileName: file.title
|
}
|
})
|
});
|
}
|
}
|
|
// 合并结果
|
// this.results = [...this.results, ...lists];
|
|
// 更新是否有更多数据状态
|
this.hasMore = lists.length >= this.pageSize;
|
|
} catch (error) {
|
console.error("加载更多失败:", error);
|
} finally {
|
this.isLoadingMore = false;
|
}
|
},
|
async fetchCameraInfo() {
|
const response = await fetch("/config.json");
|
if (!response.ok) throw new Error(`请求失败: ${response.status}`);
|
const responseData = await response.json();
|
this.docUrl = responseData.docUrl;
|
console.info("docUrl:" + this.docUrl)
|
},
|
closePopover(index) {
|
this.$set(this.popoverVisible, index, false);
|
},
|
startResize(position, e) {
|
this.isResizing = true;
|
const dialog = document.querySelector(".resizable-dialog");
|
|
this.startX = e.clientX;
|
this.startY = e.clientY;
|
this.startWidth = dialog.offsetWidth;
|
this.startHeight = dialog.offsetHeight;
|
this.startLeft = dialog.offsetLeft;
|
this.startTop = dialog.offsetTop;
|
|
document.addEventListener("mousemove", this.handleResize(position));
|
document.addEventListener("mouseup", this.stopResize);
|
},
|
handleResize(position) {
|
return (e) => {
|
if (!this.isResizing) return;
|
|
const dialog = document.querySelector(".resizable-dialog");
|
const deltaX = e.clientX - this.startX;
|
const deltaY = e.clientY - this.startY;
|
|
// 限制最小尺寸
|
const minWidth = 400;
|
const minHeight = 300;
|
|
switch (position) {
|
case "top":
|
dialog.style.height =
|
Math.max(minHeight, this.startHeight - deltaY) + "px";
|
dialog.style.top = `${this.startTop + deltaY}px`;
|
break;
|
case "bottom":
|
dialog.style.height =
|
Math.max(minHeight, this.startHeight + deltaY) + "px";
|
break;
|
case "left":
|
dialog.style.width =
|
Math.max(minWidth, this.startWidth - deltaX) + "px";
|
dialog.style.left = `${this.startLeft + deltaX}px`;
|
break;
|
case "right":
|
dialog.style.width =
|
Math.max(minWidth, this.startWidth + deltaX) + "px";
|
break;
|
case "top-left":
|
dialog.style.width =
|
Math.max(minWidth, this.startWidth - deltaX) + "px";
|
dialog.style.height =
|
Math.max(minHeight, this.startHeight - deltaY) + "px";
|
dialog.style.left = `${this.startLeft + deltaX}px`;
|
dialog.style.top = `${this.startTop + deltaY}px`;
|
break;
|
case "top-right":
|
dialog.style.width =
|
Math.max(minWidth, this.startWidth + deltaX) + "px";
|
dialog.style.height =
|
Math.max(minHeight, this.startHeight - deltaY) + "px";
|
dialog.style.top = `${this.startTop + deltaY}px`;
|
break;
|
case "bottom-left":
|
dialog.style.width =
|
Math.max(minWidth, this.startWidth - deltaX) + "px";
|
dialog.style.height =
|
Math.max(minHeight, this.startHeight + deltaY) + "px";
|
dialog.style.left = `${this.startLeft + deltaX}px`;
|
break;
|
case "bottom-right":
|
dialog.style.width =
|
Math.max(minWidth, this.startWidth + deltaX) + "px";
|
dialog.style.height =
|
Math.max(minHeight, this.startHeight + deltaY) + "px";
|
break;
|
}
|
};
|
},
|
|
stopResize() {
|
this.isResizing = false;
|
document.removeEventListener("mousemove", this.handleResize);
|
document.removeEventListener("mouseup", this.stopResize);
|
},
|
// 实时监控方法
|
handleRealTimeMonitor() {
|
this.realTimeVisible = true;
|
},
|
handleHistorySelected(chatId) {
|
this.showAIRetrieval = true; // 切换组件
|
this.selectedChatId = chatId; // 保存chatId
|
// this.$nextTick(() => {
|
// this.$refs.aiRetrieval.loadChat(); // 触发子组件加载
|
// });
|
},
|
handleAiRetrievalSelected(params) {
|
console.info("params:" + params)
|
//根据id查询数据
|
this.idsList = params;
|
this.handleSearch()
|
},
|
handleHistoryClick() {
|
this.showAIRetrieval = false;
|
this.isSidebarCollapsed = false;
|
},
|
handleNewSession() {
|
// 调用AI检索组件的重置方法
|
if (
|
this.$refs.aiRetrieval &&
|
typeof this.$refs.aiRetrieval.reset === "function"
|
) {
|
this.$refs.aiRetrieval.reset();
|
}
|
// 保持侧边栏展开状态
|
this.isSidebarCollapsed = false;
|
this.showAIRetrieval = true;
|
},
|
toggleSidebar() {
|
this.isSidebarCollapsed = !this.isSidebarCollapsed;
|
},
|
// 修改后的点击处理方法
|
handleCardClick(item) {
|
this.selectedItemId = item.id;
|
this.showDetail(item);
|
},
|
// getLevelType(level) {
|
// const typeMap = {
|
// '1': 'danger',
|
// '2': 'warning',
|
// '3': 'primary',
|
// '4': 'info',
|
// '5': 'success'
|
// }
|
// return typeMap[level] || 'info'
|
// },
|
// 获取筛选条件选项
|
|
async fetchFilterOptions() {
|
try {
|
const tasks = await surey.getTasks({
|
//检测内容
|
page: 1,
|
pageSize: 999,
|
});
|
this.filterOptions.tasks = tasks.data.list;
|
const cameras = await surey.getCameras(); //视频点位
|
this.filterOptions.cameras = cameras.data;
|
const warnings = await surey.getWarnings({
|
//预警规则
|
page: 1,
|
pageSize: 999,
|
});
|
this.filterOptions.rules = warnings.data.list;
|
|
const events = await surey.getEvents(); //事件等级
|
this.filterOptions.levels = events.data;
|
// console.info(this.filterOptions.levels)
|
} catch (error) {
|
console.error("获取筛选选项失败:", error);
|
this.$message.error("筛选选项加载失败");
|
}
|
},
|
// 格式化开始时间(保持原时间)
|
formatStartDateTime(date) {
|
if (!date) return null;
|
const d = new Date(date);
|
const pad = (num) => num.toString().padStart(2, "0");
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
|
d.getDate()
|
)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
},
|
|
// 格式化结束时间(固定为 23:59:59)
|
formatEndDateTime(date) {
|
if (!date) return null;
|
const d = new Date(date);
|
d.setHours(23, 59, 59); // 强制设置为当天的 23:59:59
|
const pad = (num) => num.toString().padStart(2, "0");
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
|
d.getDate()
|
)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
},
|
// 查询方法
|
async handleSearch() {
|
console.info("this.idsList:" + this.idsList)
|
this.isLoading = true; // 开始加载
|
// console.info(ids)
|
try {
|
this.currentPage = 1;
|
const params = {
|
ids: this.idsList,
|
page: 1,
|
pageSize: this.pageSize,
|
};
|
|
const response = await surey.getSurveys(params);
|
const lists = response.data.list || [];
|
this.results = [];
|
if (lists) {
|
for (let i = 0; i < lists.length; i++) {
|
this.results.push({
|
task_names: lists[i].task_name,
|
video_name: lists[i].video_name,
|
image_path: "/api-img" + lists[i].image_path,
|
video_path: "/api-img" + lists[i].video_path,
|
detect_time: lists[i].detect_time,
|
event_levels: lists[i].event_level_name,
|
zh_desc_class: lists[i].zh_desc_class,
|
is_warning: lists[i].is_warning,
|
is_desc: lists[i].is_desc,
|
video_point_id: lists[i].video_point_id,
|
rule_names: lists[i].rule_names,
|
knowledge_documents: lists[i].knowledge_documents.map(file => {
|
return {
|
...file,
|
file_url: "/api-img" + file.file_url,
|
fileName: file.title
|
}
|
}),
|
risk_description: lists[i].risk_description,
|
suggestion: lists[i].suggestion
|
});
|
}
|
}
|
this.totalResults = response.data.pagination.total;
|
// 更新是否有更多数据状态
|
this.hasMore = lists.length >= this.pageSize;
|
// console.info(response.data)
|
} catch (error) {
|
console.error("查询失败:", error);
|
this.$message.error("查询失败,请稍后重试");
|
} finally {
|
this.isLoading = false; // 结束加载
|
}
|
},
|
// 新增详情展示方法
|
showDetail(item) {
|
// console.info(item)
|
this.backendData = item.is_warning == 1 ? true : false;
|
// console.info(item.is_warning)
|
this.currentMediaType = "image";
|
this.detailItem = {
|
...item,
|
task: "生产任务管控", // 根据图片信息添加任务名称
|
};
|
// this.detailItem.image_path = 'http://192.168.1.232:7010/' + item.image_path
|
// this.detailItem.video_path = 'http://192.168.1.232:7010/' + item.video_path
|
this.detailItem.image_path = item.image_path;
|
this.detailItem.video_path = item.video_path;
|
this.detailItem.is_warning = item.is_warning;
|
this.detailItem.suggestion = item.suggestion;
|
this.detailItem.risk_description = item.risk_description;
|
this.detailVisible = true;
|
// console.info(item)
|
},
|
// 分页处理
|
handlePageChange(page) {
|
this.currentPage = page;
|
this.handleSearch([]);
|
},
|
// 重置筛选条件
|
resetFilter() {
|
this.filter = {
|
keyword: "",
|
task: "",
|
timeRange: [],
|
level: "",
|
camera: "",
|
};
|
this.currentPage = 1;
|
this.handleSearch([]);
|
},
|
// 获取文档预览URL
|
getPreviewUrl(doc) {
|
// 获取文件扩展名
|
const extension = this.getFileExtension(doc.fileName);
|
|
// PDF使用直接访问
|
if (extension === 'pdf') {
|
return doc.file_url;
|
}
|
|
// Office文档使用微软预览服务
|
// if (['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(extension)) {
|
// return `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(doc.file_url)}`;
|
// }
|
|
// 其他类型直接返回
|
return doc.file_url;
|
},
|
getPreviewUrl2(id) {
|
window.location.href = "/api/v1/knowledge/download?id=" + id
|
// window.location.href="http://192.168.1.176:8088/v1/knowledge/download?id="+id
|
},
|
|
// 获取文件扩展名
|
getFileExtension(filename) {
|
const parts = filename.split('.');
|
return parts.length > 1 ? parts.pop().toLowerCase() : '';
|
},
|
},
|
watch: {
|
detailVisible(newVal) {
|
if (!newVal) {
|
this.selectedItemId = null; // 关闭弹窗时清除选中状态
|
}
|
},
|
},
|
};
|
</script>
|
<style>
|
/* 全局生效,可覆盖 tooltip */
|
.my-tooltip {
|
max-width: 540px !important;
|
color: #606266 !important;
|
}
|
</style>
|
<style lang="scss" scoped>
|
|
/* 新增图片网格布局样式 */
|
.image-grid-container {
|
width: 100%;
|
overflow: hidden; /* 超出部分隐藏 */
|
}
|
|
.image-grid {
|
display: flex;
|
flex-wrap: wrap;
|
margin: -10px; /* 负边距抵消包裹元素的边距 */
|
width: 100%;
|
}
|
|
.image-card-wrapper {
|
margin: 10px; /* 设置卡片间距 */
|
// box-sizing: border-box;
|
// transition: width 0.3s ease; /* 添加平滑过渡效果 */
|
min-width: 300px; /* 卡片最小宽度 */
|
flex-shrink: 0; /* 防止卡片缩小 */
|
}
|
|
|
.right-btn {
|
position: absolute;
|
right: 8%;
|
top: 50%;
|
transform: translateY(-50%);
|
/* 垂直居中 */
|
}
|
.right-btn2 {
|
position: absolute;
|
right: 10.5%;
|
top: 74.5%;
|
transform: translateY(-50%);
|
/* 垂直居中 */
|
}
|
|
.time-icon {
|
width: 16px;
|
height: 16px;
|
margin-right: 20px;
|
vertical-align: middle;
|
}
|
|
.time-icon2 {
|
width: 16px;
|
height: 16px;
|
margin-right: 0px;
|
vertical-align: middle;
|
}
|
|
/* 关闭按钮样式 */
|
.el-icon-close {
|
position: absolute;
|
top: 10px;
|
right: 5px;
|
padding: 0;
|
width: 24px;
|
height: 24px;
|
font-size: 14px;
|
color: #909399;
|
background: none;
|
border: none;
|
cursor: pointer;
|
transition: all 0.2s;
|
}
|
|
/* 新增气泡内容样式 */
|
.task-popover-content {
|
max-height: 100px;
|
overflow-y: auto;
|
padding: 20px 15px 15px 15px;
|
/* 增加顶部空间给关闭按钮 */
|
line-height: 1.5;
|
word-break: break-word;
|
white-space: pre-line;
|
border-radius: 10px;
|
|
/* 自定义滚动条样式 */
|
&::-webkit-scrollbar {
|
width: 4px;
|
/* 缩小滚动条宽度 */
|
background-color: transparent;
|
}
|
|
&::-webkit-scrollbar-track {
|
background: transparent;
|
/* 隐藏轨道 */
|
}
|
|
&::-webkit-scrollbar-thumb {
|
background-color: #c0c4cc;
|
/* 设置滑块颜色 */
|
border-radius: 2px;
|
}
|
|
/* 移除滚动条箭头 */
|
&::-webkit-scrollbar-button {
|
display: none;
|
/* 隐藏上下箭头 */
|
}
|
}
|
|
.resizable-dialog {
|
position: fixed !important;
|
margin: 0 !important;
|
padding-top: 0px;
|
min-width: 200px;
|
min-height: 300px;
|
overflow: auto;
|
top: 50% !important;
|
left: 50% !important;
|
transform: translate(-50%, -50%) !important;
|
}
|
|
.resize-handle {
|
position: absolute;
|
background: #409eff !important;
|
z-index: 9999;
|
opacity: 0;
|
transition: opacity 0.2s;
|
}
|
|
.resize-handle:hover {
|
opacity: 1;
|
}
|
|
/* 各方向手柄定位 */
|
.top {
|
top: 0;
|
left: 0;
|
right: 0;
|
height: 4px;
|
cursor: ns-resize;
|
}
|
|
.bottom {
|
bottom: 0;
|
left: 0;
|
right: 0;
|
height: 4px;
|
cursor: ns-resize;
|
}
|
|
.left {
|
top: 0;
|
left: 0;
|
width: 4px;
|
bottom: 0;
|
cursor: ew-resize;
|
}
|
|
.right {
|
top: 0;
|
right: 0;
|
width: 4px;
|
bottom: 0;
|
cursor: ew-resize;
|
}
|
|
.top-left {
|
top: 0;
|
left: 0;
|
width: 10px;
|
height: 10px;
|
cursor: nwse-resize;
|
}
|
|
.top-right {
|
top: 0;
|
right: 0;
|
width: 10px;
|
height: 10px;
|
cursor: nesw-resize;
|
}
|
|
.bottom-left {
|
bottom: 0;
|
left: 0;
|
width: 10px;
|
height: 10px;
|
cursor: nesw-resize;
|
}
|
|
.bottom-right {
|
bottom: 0;
|
right: 0;
|
width: 10px;
|
height: 10px;
|
cursor: nwse-resize;
|
}
|
|
.el-dialog__body {
|
height: calc(100% - 54px);
|
overflow: auto;
|
}
|
|
.fold-icon {
|
width: 24px;
|
height: 24px;
|
cursor: pointer;
|
transition: transform 0.3s ease;
|
margin: 8px;
|
|
&:hover {
|
opacity: 0.8;
|
filter: drop-shadow(0 0 2px rgba(11, 113, 216, 0.5));
|
}
|
|
&.reverse {
|
transform: rotate(180deg);
|
}
|
}
|
|
/* ai-retrieval容器样式 */
|
.ai-retrieval-container {
|
position: absolute;
|
// left: 5px;
|
width: 360px;
|
// height: 1000px;
|
z-index: 1000;
|
background: rgb(245, 244, 244);
|
// box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
|
}
|
|
/* 新增多值显示样式 */
|
.multi-value {
|
display: inline-block;
|
max-width: 540px;
|
// white-space: nowrap;
|
overflow: hidden;
|
// text-overflow: ellipsis;
|
}
|
|
.desc_class {
|
// max-height: 380px;
|
overflow-y: auto;
|
}
|
|
.multi-value2 {
|
display: inline-block;
|
// max-height: 380px;
|
}
|
|
.stats-header {
|
margin-bottom: 20px;
|
|
.ai-avatar {
|
display: flex;
|
align-items: flex-start; // 顶部对齐
|
|
.header-text {
|
margin-left: 10px;
|
|
.content-title {
|
text-align: left;
|
margin: 5px 0 10px;
|
color: #0e3eaa;
|
}
|
|
.stats-numbers {
|
font-size: 12px;
|
text-align: left;
|
}
|
}
|
|
.header-actions {
|
flex: 1;
|
text-align: right;
|
margin-top: 10px;
|
}
|
}
|
}
|
|
.results-container {
|
padding: 0 15px;
|
// min-height: 600px;
|
overflow-x: hidden; /* 隐藏横向滚动条 */
|
overflow-y: auto; /* 保留纵向滚动 */
|
/* 新增滚动条 */
|
height: 900px;
|
|
|
|
.result-card {
|
border-radius: 8px;
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
border: none;
|
position: relative; // 为绝对定位提供基准
|
overflow: visible; // 防止按钮被裁剪
|
|
.image-wrapper {
|
position: relative;
|
// height: 200px;
|
overflow: visible;
|
border-radius: 6px 6px 0 0;
|
|
.result-image {
|
width: 100%;
|
// height: 130px;
|
object-fit: cover;
|
transition: transform 0.3s;
|
}
|
|
.image-overlay {
|
position: absolute;
|
bottom: 0;
|
left: 0;
|
right: 0;
|
background: rgba(0, 0, 0, 0.6);
|
/* 半透明黑色背景 */
|
padding: 5px 10px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
z-index: 2;
|
/* 确保在图片上方 */
|
}
|
|
.check-item {
|
color: white;
|
font-size: 12px;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
max-width: 70%;
|
}
|
|
.level-tag {
|
z-index: 3;
|
/* 确保在覆盖层上方 */
|
transform: scale(0.9);
|
margin: 2px;
|
color: #fa0505;
|
background-color: #f3e1e1;
|
}
|
}
|
|
.card-content {
|
padding: 15px;
|
|
.meta-info {
|
.time-info {
|
display: flex;
|
text-align: left;
|
align-items: center;
|
margin-bottom: 10px;
|
color: #909399;
|
width: 100%;
|
margin-bottom: 10px;
|
|
.el-icon-time {
|
color: #409eff !important;
|
margin-right: 20px;
|
font-size: 16px;
|
}
|
|
span {
|
font-size: 13px;
|
margin-right: 20px;
|
}
|
|
.el-icon-document {
|
color: #034914;
|
}
|
|
.detect-time {
|
flex-shrink: 0;
|
color: #909399;
|
font-size: 13px;
|
}
|
}
|
|
.device-info {
|
// display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.camera-info {
|
// display: flex;
|
position: relative;
|
text-align: left;
|
align-items: center;
|
|
i {
|
color: #409eff !important;
|
margin-right: 20px;
|
font-size: 16px;
|
}
|
|
span {
|
font-size: 14px;
|
color: #303133;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
.pagination-wrapper {
|
// position: fixed;
|
right: 30px;
|
bottom: 30px;
|
background: #fff;
|
padding: 10px 20px;
|
border-radius: 4px;
|
// box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
}
|
|
// 调整布局结构
|
.statistics-container {
|
display: flex;
|
height: 98vh; // 新增
|
|
.left-sidebar {
|
width: 320px;
|
transition: all 0.3s ease;
|
left: 0;
|
// height: 100vh;
|
z-index: 1000;
|
background: #fff;
|
box-shadow: 1px 0 10px rgba(0, 0, 0, 0.1);
|
|
padding: 10px;
|
border-right: 1px solid #ebeef5;
|
position: relative;
|
padding-bottom: 40px;
|
/* 为底部按钮留出空间 */
|
/* 为绝对定位创建参照 */
|
|
.session-buttons {
|
// position: absolute;
|
bottom: 20px;
|
left: 20px;
|
right: 20px;
|
display: flex;
|
gap: 0;
|
|
.el-button {
|
height: 50px;
|
border-radius: 5px;
|
transition: all 0.3s ease;
|
background-color: #e1ebff !important;
|
color: #2482ff;
|
border: 1px solid #e1ebff !important;
|
font-size: 16px !important;
|
padding: 0 12px;
|
}
|
|
::v-deep .el-button {
|
background-color: #e1ebff !important;
|
}
|
}
|
|
&.collapsed {
|
width: 40px;
|
|
.ai-avatar {
|
flex-direction: column;
|
align-items: center;
|
padding: 10px 0;
|
|
.avatar-img {
|
margin: 0;
|
width: 51px;
|
height: 35px;
|
}
|
}
|
|
.header-actions i {
|
transform: rotate(180deg);
|
margin-top: 10px;
|
}
|
}
|
|
.header-actions {
|
i {
|
transition: all 0.3s ease;
|
cursor: pointer;
|
font-size: 20px;
|
color: #666;
|
|
&:hover {
|
color: #0b71d8;
|
}
|
|
&.reverse {
|
transform: rotate(180deg);
|
}
|
}
|
}
|
|
.right-content {
|
transition: margin 0.3s ease;
|
padding: 20px;
|
min-height: 100vh;
|
background: #f5f6fa;
|
}
|
|
.ai-retrieval-container {
|
width: 100%;
|
height: calc(100% - 150px);
|
/* 根据实际布局调整高度 */
|
position: relative;
|
box-shadow: none;
|
background: #fff;
|
}
|
|
.el-checkbox {
|
margin-left: 15px;
|
display: block;
|
text-align: left;
|
}
|
|
.el-form-item__content {
|
margin-left: 0 !important;
|
}
|
}
|
|
.right-content {
|
flex: 1;
|
margin-left: 20px;
|
position: relative;
|
box-shadow: 1px 0 10px rgba(0, 0, 0, 0.1);
|
padding: 20px;
|
padding-top: 0px;
|
border-left: 1px solid #ebeef5;
|
|
.right-header {
|
display: flex;
|
margin-bottom: 20px;
|
border-bottom: 1px solid #ebeef5;
|
padding-bottom: 10px;
|
justify-content: space-between;
|
height: 70px;
|
/* 新增:左右两端对齐 */
|
|
.content-title{
|
text-align: left;
|
margin: 15px 0 0 0;
|
}
|
.header-actions-right {
|
margin-top: 20px;
|
|
.action-btn {
|
height: 40px;
|
margin-bottom: 0px;
|
padding: 10px 20px;
|
border-radius: 6px;
|
letter-spacing: 0.5px;
|
}
|
}
|
}
|
}
|
}
|
|
.form-actions {
|
margin-top: 50px;
|
display: flex;
|
gap: 10px; // 按钮间距
|
|
.full-width-btn {
|
flex: 1; // 等分剩余空间
|
margin-left: 0 !important;
|
}
|
|
// 清除Element默认边距
|
::v-deep .el-button {
|
margin-left: 0;
|
margin-right: 0;
|
}
|
}
|
|
// 详情弹窗样式
|
.detail-dialog {
|
.el-dialog__header {
|
border-bottom: 1px solid #ebeef5;
|
}
|
|
.media-switch {
|
margin: -50px 0 15px;
|
text-align: left;
|
|
.media-tab {
|
&.is-active {
|
background: #409eff !important;
|
border-color: #409eff !important;
|
color: white;
|
}
|
}
|
}
|
|
.media-container {
|
height: 350px;
|
border: 1px solid #ebeef5;
|
border-radius: 4px;
|
margin-bottom: 20px;
|
position: relative;
|
overflow: hidden; // 添加溢出隐藏
|
|
.main-image {
|
height: 100%;
|
padding: 0px;
|
|
.detail-img {
|
width: 100%;
|
height: 100%;
|
object-fit: contain;
|
}
|
}
|
|
.video-section {
|
height: 100%;
|
width: 100%;
|
|
.video-placeholder {
|
width: 100%;
|
height: 100%;
|
position: relative;
|
|
video {
|
max-width: 100%;
|
max-height: 100%;
|
display: block;
|
margin: 0 auto;
|
}
|
}
|
}
|
}
|
|
.info-container {
|
height: 400px;
|
// overflow-y: auto;
|
|
::v-deep .el-descriptions__body {
|
background: white;
|
}
|
|
.info-item {
|
padding: 12px 10px;
|
|
&>.el-descriptions-item__label {
|
color: #606266;
|
width: 90px;
|
}
|
}
|
|
.red-text {
|
color: #f56c6c !important;
|
}
|
|
.blue-text {
|
color: #409eff !important;
|
}
|
|
.doc-link {
|
padding-left: 10px;
|
text-decoration: none;
|
color: #1b50e4;
|
// display: inline-block;
|
// padding: 5px 8px;
|
// border-radius: 4px;
|
// transition: all 0.3s;
|
// color: #165DFF;
|
|
&:hover {
|
cursor: pointer;
|
}
|
}
|
|
::v-deep .el-descriptions-item__label {
|
color: black !important;
|
font-weight: 600 !important;
|
}
|
}
|
}
|
|
/* 右侧对齐样式 */
|
.detail-dialog {
|
position: fixed !important;
|
top: 50% !important;
|
left: auto !important;
|
right: 20px !important;
|
transform: translateY(-50%) !important;
|
width: 660px !important;
|
margin: 0 !important;
|
z-index: 2000 !important;
|
}
|
|
::v-deep .el-dialog {
|
|
// margin-right: 0px;
|
.el-divider--horizontal {
|
margin: 12px 0;
|
}
|
}
|
|
/* 表格表头样式 */
|
.header-gradient {
|
background: radial-gradient(circle at 20% 30%, #0e5397, #2482FF);
|
-webkit-background-clip: text;
|
background-clip: text;
|
color: transparent;
|
font-weight: bold;
|
font-size: 35px;
|
}
|
|
.header-gradient2 {
|
font-size: 18px;
|
background: radial-gradient(circle at 20% 30%, #165DFF, #01040a);
|
-webkit-background-clip: text;
|
background-clip: text;
|
}
|
|
/* 新增加载状态样式 */
|
.loading-container {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
height: 300px;
|
color: #606266;
|
font-size: 16px;
|
|
.el-icon {
|
margin-bottom: 15px;
|
animation: rotating 1.5s linear infinite;
|
|
@keyframes rotating {
|
0% {
|
transform: rotate(0deg);
|
}
|
|
100% {
|
transform: rotate(360deg);
|
}
|
}
|
}
|
}
|
|
.ellipsis {
|
display: inline-block;
|
/* 或 block */
|
// max-width: 100%; /* 根据实际容器宽度调整 */
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
/* 关键:禁止换行 */
|
}
|
</style>
|