|
@@ -18,10 +18,13 @@
|
|
|
</template>
|
|
|
<template v-else>
|
|
|
<div class="body-head details-head">
|
|
|
- <h3 style="visibility: hidden">场景管理</h3>
|
|
|
+ <h3 style="visibility: hidden">绘图管理</h3>
|
|
|
<div>
|
|
|
<template v-if="isDraw">
|
|
|
- <el-button type="primary" @click="gotoDraw(BoardType.map, -1)">
|
|
|
+ <!-- <el-button type="primary" @click="gotoDraw(BoardType.map, -1)">
|
|
|
+ 创建{{ BoardTypeDesc[BoardType.map] }}
|
|
|
+ </el-button> -->
|
|
|
+ <el-button type="primary" @click="openMapDialog">
|
|
|
创建{{ BoardTypeDesc[BoardType.map] }}
|
|
|
</el-button>
|
|
|
<el-button type="primary" @click="gotoDraw(BoardType.scene, -1)">
|
|
@@ -33,8 +36,7 @@
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <el-table
|
|
|
+ <!-- <el-table
|
|
|
:data="files"
|
|
|
class="table-list"
|
|
|
tooltip-effect="dark"
|
|
@@ -87,7 +89,113 @@
|
|
|
</span>
|
|
|
<span class="oper-span delBtn" @click="del(row)"> 删除 </span>
|
|
|
</el-table-column>
|
|
|
- </el-table>
|
|
|
+ </el-table> -->
|
|
|
+
|
|
|
+ <!-- 卡片网格布局 -->
|
|
|
+ <div class="file-grid-container">
|
|
|
+ <div
|
|
|
+ class="file-card"
|
|
|
+ v-for="(file, index) in files"
|
|
|
+ :key="file.filesId"
|
|
|
+ >
|
|
|
+ <!-- 卡片图片容器 -->
|
|
|
+ <div class="card-image-container">
|
|
|
+ <el-image
|
|
|
+ ref="imageRef"
|
|
|
+ :src="file.filesUrl"
|
|
|
+ :preview-src-list="srcList"
|
|
|
+ :initial-index="index"
|
|
|
+ fit="cover"
|
|
|
+ class="card-image"
|
|
|
+ :hide-on-click-modal="true"
|
|
|
+ :preview-teleported="true"
|
|
|
+ >
|
|
|
+ <template #error>
|
|
|
+ <div class="image-error">
|
|
|
+ <el-icon size="40" color="#c0c4cc">
|
|
|
+ <Document />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-image>
|
|
|
+
|
|
|
+ <!-- 悬浮操作按钮 -->
|
|
|
+ <div class="card-overlay">
|
|
|
+ <div class="card-actions">
|
|
|
+ <el-button
|
|
|
+ class="card-overlay-btn"
|
|
|
+ size="default"
|
|
|
+ circle
|
|
|
+ @click.stop="previewImage(index)"
|
|
|
+ title="查看"
|
|
|
+ >
|
|
|
+ <el-icon :size="20"><View /></el-icon>
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ class="card-overlay-btn"
|
|
|
+ size="default"
|
|
|
+ circle
|
|
|
+ @click.stop="gotoDraw(file.imgType!, file.filesId)"
|
|
|
+ v-if="file.imgType !== null"
|
|
|
+ title="编辑"
|
|
|
+ >
|
|
|
+ <el-icon :size="20"><Edit /></el-icon>
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ class="card-overlay-btn"
|
|
|
+ size="default"
|
|
|
+ circle
|
|
|
+ @click.stop="del(file)"
|
|
|
+ title="删除"
|
|
|
+ >
|
|
|
+ <el-icon :size="20"><Delete /></el-icon>
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 卡片底部:文件名 -->
|
|
|
+ <div class="card-footer">
|
|
|
+ <div class="file-title">
|
|
|
+ <span v-if="!inputCaseTitles.includes(file)" class="title-text">
|
|
|
+ {{ file.filesTitle }}
|
|
|
+ <el-icon class="edit-title" @click="inputCaseTitles.push(file)">
|
|
|
+ <EditPen />
|
|
|
+ </el-icon>
|
|
|
+ </span>
|
|
|
+ <template v-else>
|
|
|
+ <ElInput
|
|
|
+ v-model="file.filesTitle"
|
|
|
+ placeholder="请输入文件名"
|
|
|
+ focus
|
|
|
+ :maxlength="50"
|
|
|
+ size="default"
|
|
|
+ class="edit-input"
|
|
|
+ >
|
|
|
+ <template #append>
|
|
|
+ <el-button type="primary" plain @click="updateFileTitle(file)">
|
|
|
+ 确定
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </ElInput>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-image-viewer
|
|
|
+ v-if="showPreview"
|
|
|
+ :url-list="srcList"
|
|
|
+ show-progress
|
|
|
+ :initial-index="0"
|
|
|
+ @close="showPreview = false"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 地图选择弹窗 -->
|
|
|
+ <CreatMap
|
|
|
+ v-model="showMapDialog"
|
|
|
+ @confirm="handleMapConfirm"
|
|
|
+ />
|
|
|
</template>
|
|
|
</div>
|
|
|
</template>
|
|
@@ -110,10 +218,12 @@ import {
|
|
|
} from "@/store/caseFile";
|
|
|
import { getCaseInfo, updateCaseInfo } from "@/store/case";
|
|
|
import { appConstant } from "@/app";
|
|
|
-import { ElIcon, ElInput, ElMessage } from "element-plus";
|
|
|
+import { ElIcon, ElInput, ElMessage, ElImage, ElButton, ImageInstance } from "element-plus";
|
|
|
+import { EditPen, Document, View, Edit, Delete } from "@element-plus/icons-vue";
|
|
|
import Photos from "./photos/index.vue";
|
|
|
import Records from "./records/index.vue";
|
|
|
import Manifest from "./records/manifest.vue";
|
|
|
+import CreatMap from "./drawMap/creatMap.vue";
|
|
|
|
|
|
const props = defineProps<{
|
|
|
caseId?: number;
|
|
@@ -169,6 +279,41 @@ watchEffect(() => {
|
|
|
const isDraw = computed(() => currentTypeId.value === FileDrawType);
|
|
|
|
|
|
const files = ref<CaseFile[]>([]);
|
|
|
+
|
|
|
+// 计算预览图片列表
|
|
|
+const srcList = computed(() => {
|
|
|
+ return files.value.map(file => file.filesUrl);
|
|
|
+});
|
|
|
+
|
|
|
+// 预览图片方法
|
|
|
+const imageRef = ref<ImageInstance>()
|
|
|
+const showPreview = ref(false)
|
|
|
+const previewImage = (index: number) => {
|
|
|
+ const file = files.value[index];
|
|
|
+ const ext = file.filesUrl
|
|
|
+ .substring(file.filesUrl.lastIndexOf("."))
|
|
|
+ .toLocaleLowerCase();
|
|
|
+
|
|
|
+ // 如果是图片文件,让 el-image 的预览功能自动处理
|
|
|
+ const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
|
|
|
+ console.log(imageRef.value, 999)
|
|
|
+ if (imageExts.includes(ext)) {
|
|
|
+ showPreview.value = true
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果是其他文件类型,使用原来的查看逻辑
|
|
|
+ const appId = import.meta.env.VITE_APP_APP || 'fire';
|
|
|
+ if ([".raw", ".dcm"].includes(ext)) {
|
|
|
+ window.open(
|
|
|
+ `/${appId}/xfile-viewer/index.html?file=${file.filesUrl}&name=${file.filesTitle}&time=` +
|
|
|
+ Date.now()
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ window.open(file.filesUrl + "?time=" + Date.now());
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
const refresh = async () => {
|
|
|
files.value = await getCaseFiles({
|
|
|
caseId: caseId.value!,
|
|
@@ -209,6 +354,36 @@ const gotoDraw = (type: BoardType, id: number) => {
|
|
|
params: { caseId: caseId.value!, type, id },
|
|
|
});
|
|
|
};
|
|
|
+// 地图弹窗相关
|
|
|
+const showMapDialog = ref(false)
|
|
|
+
|
|
|
+// 打开地图选择弹窗,新版本地图选择
|
|
|
+const openMapDialog = () => {
|
|
|
+ showMapDialog.value = true
|
|
|
+}
|
|
|
+
|
|
|
+// 处理地图选择确认
|
|
|
+const handleMapConfirm = async (location: any) => {
|
|
|
+ console.log('选择的地图位置:', location)
|
|
|
+ // 这里可以将位置信息保存到案件中,或者创建地图绘图
|
|
|
+ try {
|
|
|
+ // 可以调用相关API保存位置信息
|
|
|
+ // 或者直接跳转到绘图页面
|
|
|
+ await router.push({
|
|
|
+ name: RouteName.drawCaseFile,
|
|
|
+ params: {
|
|
|
+ caseId: caseId.value!,
|
|
|
+ type: BoardType.map,
|
|
|
+ id: -1
|
|
|
+ },
|
|
|
+ query: {
|
|
|
+ location: JSON.stringify(location)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ console.error('处理地图位置失败:', error)
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
onMounted(async () => {
|
|
|
try {
|
|
@@ -282,9 +457,142 @@ onUnmounted(() => {
|
|
|
align-items: flex-start;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
.edit-title {
|
|
|
cursor: pointer;
|
|
|
margin-left: 10px;
|
|
|
}
|
|
|
+
|
|
|
+// 卡片网格布局样式
|
|
|
+.file-grid-container {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fill, 387px);
|
|
|
+ gap: 16px;
|
|
|
+ padding: 16px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.file-card {
|
|
|
+ background: #ffffff;
|
|
|
+ // transition: all 0.3s ease;
|
|
|
+ width: 387px;
|
|
|
+ height: 303px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ // box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
+ // transform: translateY(-2px);
|
|
|
+
|
|
|
+ .card-overlay {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.card-image-container {
|
|
|
+ position: relative;
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.card-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.image-error {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.card-overlay {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: rgba(0, 0, 0, 0.4);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ opacity: 0;
|
|
|
+ transition: opacity 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.card-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ .card-overlay-btn{
|
|
|
+ background: transparent;
|
|
|
+ border: none;
|
|
|
+ color: #F2F2F2;
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.card-footer {
|
|
|
+ padding: 12px 0;
|
|
|
+ background: #ffffff;
|
|
|
+}
|
|
|
+
|
|
|
+.file-title {
|
|
|
+ .title-text {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #303133;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ word-break: break-all;
|
|
|
+ line-height: 1.4;
|
|
|
+ }
|
|
|
+
|
|
|
+ .edit-input {
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
+ height: 30px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-input-group__append) {
|
|
|
+ .el-button {
|
|
|
+ height: 30px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.file-time {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ margin-top: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+// 响应式设计
|
|
|
+@media (max-width: 1200px) {
|
|
|
+ .file-grid-container {
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .file-grid-container {
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .file-card {
|
|
|
+ height: 240px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-footer {
|
|
|
+ padding: 8px 0;
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|
|
|
|