|
|
@@ -280,7 +280,7 @@
|
|
|
</div>
|
|
|
<div v-else class="records-preview">
|
|
|
<h3 class="title">上传文件</h3>
|
|
|
- <pre class="preview-text">{{ inquestData.filesTitle || '-' }}</pre>
|
|
|
+ <div class="preview-text" @click="openInquestFile(inquestData)">{{ inquestData.filesTitle || '-' }}</div>
|
|
|
</div>
|
|
|
<el-image-viewer
|
|
|
v-if="showViewer"
|
|
|
@@ -310,7 +310,7 @@
|
|
|
</div>
|
|
|
<div v-else class="records-preview">
|
|
|
<h3 class="title">上传文件</h3>
|
|
|
- <pre class="preview-text">{{ extractionData.filesTitle || '-' }}</pre>
|
|
|
+ <div class="preview-text" @click="openInquestFile(inquestData)">{{ extractionData.filesTitle || '-' }}</div>
|
|
|
</div>
|
|
|
<el-image-viewer
|
|
|
v-if="showViewer"
|
|
|
@@ -331,7 +331,7 @@
|
|
|
<!-- 照片卷右侧:单图预览,可点击放大 -->
|
|
|
<template v-else-if="activeTab === 'album'">
|
|
|
<div v-if="currentAlbum" class="scene-image" @click="openAlbumViewer(0)">
|
|
|
- <el-image :src="currentAlbum.images[0].url" fit="contain" class="inline-image" />
|
|
|
+ <el-image :src="currentAlbumImageUrl" fit="contain" class="inline-image" />
|
|
|
</div>
|
|
|
<div v-else class="viewer-placeholder">暂无照片卷</div>
|
|
|
<el-image-viewer
|
|
|
@@ -352,7 +352,8 @@ import RelName from './relName.vue';
|
|
|
import SiteText from './sitetext.vue';
|
|
|
import ManifestText from './manifesttext.vue';
|
|
|
// 弹窗已移除,直接跳转到绘制页面
|
|
|
-import { CaseFile, BoardType, setCaseFile, delCaseFile, getCaseFileImageInfo } from '@/store/caseFile';
|
|
|
+import { CaseFile, BoardType, setCaseFile, delCaseFile } from '@/store/caseFile';
|
|
|
+import { getCaseFileImageInfo } from '@/store/editCsae';
|
|
|
import { FileDrawType } from '@/constant/caseFile';
|
|
|
import { addCaseFile as addCaseFileDialog } from '@/view/case/quisk';
|
|
|
import { router, RouteName } from '@/router';
|
|
|
@@ -361,6 +362,7 @@ import { exportCaseInquestInfo, exportCaseDetailInfo, caseDel } from '@/store/ca
|
|
|
import { getFfmpegImageListOffline as getFfmpegImageList, caseFilesTypeGetTree, getCaseFilesOffline as getCaseFiles } from '@/store/editCsae';
|
|
|
import { getCaseInquestInfo, getCaseDetailInfo } from '@/store/case';
|
|
|
import { axios } from '@/request';
|
|
|
+import { isOfflineMode } from '@/util/offline';
|
|
|
import { saveAs } from '@/util/file-serve';
|
|
|
|
|
|
const appId = import.meta.env.VITE_APP_APP || 'fire';
|
|
|
@@ -434,7 +436,7 @@ const loadListsFromTree = async () => {
|
|
|
id: Number(item?.filesId),
|
|
|
...item,
|
|
|
title: item?.title || (item?.count ? `勘验笔录(第${item.count}次)` : `勘验笔录 ${idx + 1}`),
|
|
|
- content: typeof item?.content === 'string' ? item.content : (item?.startTime || item?.endTime ? formatInquest(item) : ''),
|
|
|
+ content: typeof item?.content === 'string' ? item.content : '',
|
|
|
}));
|
|
|
if (inspectionList.value.length) {
|
|
|
selectedInquestId.value = inspectionList.value[0]?.id ?? null;
|
|
|
@@ -455,7 +457,7 @@ const loadListsFromTree = async () => {
|
|
|
id: Number(item?.filesId),
|
|
|
...item,
|
|
|
title: item?.title || (item?.address ? `提取清单(${item.address})` : `提取清单 ${idx + 1}`),
|
|
|
- content: typeof item?.content === 'string' ? item.content : formatExtraction(item),
|
|
|
+ content: typeof item?.content === 'string' ? item.content : '',
|
|
|
}));
|
|
|
if (extractionList.value.length) {
|
|
|
selectedExtractId.value = extractionList.value[0]?.id ?? null;
|
|
|
@@ -500,19 +502,62 @@ const viewerIndex = ref(0);
|
|
|
// 现场图选择高亮索引
|
|
|
const selectedPlaneIndex = ref<number | null>(null);
|
|
|
const selectedOrientationIndex = ref<number | null>(null);
|
|
|
+const toOffline = (raw: string) => {
|
|
|
+ if (!raw) return '';
|
|
|
+ const httpHost = /^https?:\/\/[^/]+/i;
|
|
|
+ if (httpHost.test(raw)) return '.' + raw.replace(httpHost, '');
|
|
|
+ if (raw.startsWith('/')) return '.' + raw;
|
|
|
+ if (raw.startsWith('./')) return raw;
|
|
|
+ return './' + raw;
|
|
|
+ };
|
|
|
// 右侧展示的现场图当前图片
|
|
|
const currentSceneImageUrl = computed(() => {
|
|
|
+
|
|
|
+ // 离线模式:优先使用原始文件的 filesUrl 并转换为相对路径
|
|
|
+ if (isOfflineMode()) {
|
|
|
+ if (selectedPlaneIndex.value !== null && planeFiles.value[selectedPlaneIndex.value]) {
|
|
|
+ const raw = (planeFiles.value[selectedPlaneIndex.value] as any)?.filesUrl || (planeImages.value[selectedPlaneIndex.value] as any)?.url;
|
|
|
+ return toOffline(String(raw || ''));
|
|
|
+ }
|
|
|
+ if (selectedOrientationIndex.value !== null && orientationFiles.value[selectedOrientationIndex.value]) {
|
|
|
+ const raw = (orientationFiles.value[selectedOrientationIndex.value] as any)?.filesUrl || (orientationImages.value[selectedOrientationIndex.value] as any)?.url;
|
|
|
+ return toOffline(String(raw || ''));
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在线模式:保持原逻辑使用已映射的图片 url
|
|
|
if (selectedPlaneIndex.value !== null && planeImages.value[selectedPlaneIndex.value]) {
|
|
|
return planeImages.value[selectedPlaneIndex.value].url;
|
|
|
}
|
|
|
- if (
|
|
|
- selectedOrientationIndex.value !== null &&
|
|
|
- orientationImages.value[selectedOrientationIndex.value]
|
|
|
- ) {
|
|
|
+ if (selectedOrientationIndex.value !== null && orientationImages.value[selectedOrientationIndex.value]) {
|
|
|
return orientationImages.value[selectedOrientationIndex.value].url;
|
|
|
}
|
|
|
return '';
|
|
|
});
|
|
|
+const openInquestFile = (item: any) => {
|
|
|
+ if (item?.filesUrl) {
|
|
|
+ if (isOfflineMode()) {
|
|
|
+ window.open(toOffline(item.filesUrl), '_blank');
|
|
|
+ } else {
|
|
|
+ window.open(item.filesUrl, '_blank');
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+// 照片卷当前图片链接,兼容离线模式
|
|
|
+const currentAlbumImageUrl = computed(() => {
|
|
|
+ const img = currentAlbum.value?.images?.[0];
|
|
|
+ const raw = img?.url || '';
|
|
|
+ if (!raw) return '';
|
|
|
+ if (isOfflineMode()) {
|
|
|
+ const httpHost = /^https?:\/\/[^/]+/i;
|
|
|
+ if (httpHost.test(raw)) return '.' + raw.replace(httpHost, '');
|
|
|
+ if (raw.startsWith('/')) return '.' + raw;
|
|
|
+ if (raw.startsWith('./')) return raw;
|
|
|
+ return './' + raw;
|
|
|
+ }
|
|
|
+ return raw;
|
|
|
+});
|
|
|
|
|
|
const openViewer = (type: 'plane' | 'orientation', index: number) => {
|
|
|
const isPlane = type === 'plane';
|
|
|
@@ -738,7 +783,7 @@ const loadInspection = async (filesId?: number) => {
|
|
|
if (idx >= 0) {
|
|
|
inquestRawList.value[idx] = detail;
|
|
|
inquestData.value = detail || {};
|
|
|
- inspectionList.value[idx].content = formatInquest(detail || {});
|
|
|
+ inspectionList.value[idx].content = typeof (detail as any)?.content === 'string' ? (detail as any).content : '';
|
|
|
} else {
|
|
|
// 如果未找到索引,仅更新右侧数据
|
|
|
inquestData.value = res || {};
|
|
|
@@ -754,14 +799,14 @@ const loadInspection = async (filesId?: number) => {
|
|
|
id: Number(item?.id),
|
|
|
...item,
|
|
|
title: item?.count ? `勘验笔录(第${item.count}次)` : `勘验笔录 ${idx + 1}`,
|
|
|
- content: formatInquest(item),
|
|
|
+ content: typeof item?.content === 'string' ? item.content : '',
|
|
|
}));
|
|
|
if (inspectionList.value.length) {
|
|
|
selectedInquestId.value = inspectionList.value[0]?.id ?? null;
|
|
|
inquestData.value = inquestRawList.value[0] || {};
|
|
|
}
|
|
|
} else {
|
|
|
- const content = formatInquest(payload || {});
|
|
|
+ const content = typeof (payload as any)?.content === 'string' ? (payload as any).content : '';
|
|
|
inquestRawList.value = [payload || {}];
|
|
|
if (!inspectionList.value.length) {
|
|
|
inspectionList.value = [{ id: Number((payload as any)?.id), title: '勘验笔录', content }];
|
|
|
@@ -779,28 +824,7 @@ const loadInspection = async (filesId?: number) => {
|
|
|
console.error('获取勘验笔录失败:', e);
|
|
|
}
|
|
|
};
|
|
|
-// 将接口数据格式化为预览文本
|
|
|
-const formatInquest = (d: any) => {
|
|
|
- const s = d.startTime || {}; const e = d.endTime || {};
|
|
|
- const witnesses = Array.isArray(d.witnessInfo) ? d.witnessInfo.map((w: any, i: number) => `证人${i+1}:${w.name || '-'},${w.year || ''}年${w.month || ''}月${w.day || ''}日\n身份证件号码:${w.id || '-'}\n单位或住址:${w.address || '-'}\n`).join('\n') : '';
|
|
|
- return (
|
|
|
- `勘验次数: 第 ${d.count || '-'} 次勘验\n` +
|
|
|
- `勘验时间: ${s.year || ''}年${s.month || ''}月${s.day || ''}日 ${s.hour || ''}时${s.min || ''}分 至 ${e.year || ''}年${e.month || ''}月${e.day || ''}日 ${e.hour || ''}时${e.min || ''}分\n` +
|
|
|
- `勘验地点: ${d.address || '-'}\n` +
|
|
|
- `勘验人员姓名、勘验人描述(含技术员职务): ${d.userInfo || '-'}\n` +
|
|
|
- `勘验气象条件(天空、风力、温度): ${d.weather || '-'}\n\n` +
|
|
|
- `勘验情况: \n${d.situation || ''}\n\n` +
|
|
|
- `一、环境勘验\n${d.environment || ''}\n\n` +
|
|
|
- `二、初步勘验\n${d.firstInquest || ''}\n\n` +
|
|
|
- `三、细项勘验\n${d.carefulInquest || ''}\n\n` +
|
|
|
- `四、专项勘验\n${d.specialInquest || ''}\n\n` +
|
|
|
- `提取物品描述:\n${d.itemDescription || ''}\n\n` +
|
|
|
- `现场拍照制图描述:\n${d.imgDescription || ''}\n\n` +
|
|
|
- `勘验信息:\n` +
|
|
|
- `勘验负责人:${d.leader || '-'}\n记录人:${d.recorder || '-'}\n勘验人:${d.inspector || '-'}\n\n` +
|
|
|
- witnesses
|
|
|
- );
|
|
|
-};
|
|
|
+// 旧的文本格式化逻辑已由组件渲染替代,移除无用函数。
|
|
|
|
|
|
// 调取接口并填充列表(提取清单)
|
|
|
const loadExtraction = async (filesId?: number) => {
|
|
|
@@ -815,7 +839,7 @@ const loadExtraction = async (filesId?: number) => {
|
|
|
extractionRawList.value[idx] = detail;
|
|
|
extractionData.value = detail || {};
|
|
|
const prev = extractionList.value[idx] || { title: '提取清单' };
|
|
|
- extractionList.value[idx].content = formatExtraction(detail || {});
|
|
|
+ extractionList.value[idx].content = typeof (detail as any)?.content === 'string' ? (detail as any).content : '';
|
|
|
} else {
|
|
|
extractionData.value = res;
|
|
|
}
|
|
|
@@ -828,7 +852,7 @@ const loadExtraction = async (filesId?: number) => {
|
|
|
extractionList.value = payload.map((item: any, idx: number) => ({
|
|
|
id: Number(item?.id ?? item?.extractId),
|
|
|
title: item?.address ? `提取清单(${item.address})` : `提取清单 ${idx + 1}`,
|
|
|
- content: formatExtraction(item),
|
|
|
+ content: typeof item?.content === 'string' ? item.content : '',
|
|
|
}));
|
|
|
if (extractionList.value.length) {
|
|
|
selectedExtractId.value = extractionList.value[0]?.id ?? null;
|
|
|
@@ -841,7 +865,7 @@ const loadExtraction = async (filesId?: number) => {
|
|
|
(target as any)[k] = (payload as any)[k];
|
|
|
}
|
|
|
}
|
|
|
- const content = formatExtraction(target);
|
|
|
+ const content = typeof (target as any)?.content === 'string' ? (target as any).content : '';
|
|
|
if (!extractionList.value.length) {
|
|
|
extractionList.value = [{ id: Number((payload as any)?.id ?? (payload as any)?.extractId), title: '提取清单', content }];
|
|
|
selectedExtractId.value = extractionList.value[0]?.id ?? null;
|
|
|
@@ -876,38 +900,7 @@ const extractionData = ref<any>({
|
|
|
],
|
|
|
});
|
|
|
|
|
|
-const formatExtraction = (d: any) => {
|
|
|
- const time = d.time || {};
|
|
|
- const header = `起火单位/地址: ${d.address || ''}\n提取日期: ${time.year || ''}年${time.month || ''}月${time.day || ''}日\n`;
|
|
|
- const items = Array.isArray(d.detail)
|
|
|
- ? d.detail
|
|
|
- .map(
|
|
|
- (item: any, idx: number) =>
|
|
|
- `编号 ${idx + 1}:\n名称: ${item.name || ''}\n规格: ${item.spec || ''}\n数量: ${item.num || ''}\n提取部位: ${item.part || ''}\n特征: ${item.desc || ''}\n`
|
|
|
- )
|
|
|
- .join('\n')
|
|
|
- : '';
|
|
|
-
|
|
|
- const extractUsers = Array.isArray(d.extractUser)
|
|
|
- ? d.extractUser
|
|
|
- .map(
|
|
|
- (u: any) => `提取人:姓名: ${u.name || ''} 工作单位: ${u.address || ''}`
|
|
|
- )
|
|
|
- .join('\n')
|
|
|
- : '';
|
|
|
-
|
|
|
- const witnesses = Array.isArray(d.witnessInfo)
|
|
|
- ? `\n证人或当事人:\n` +
|
|
|
- d.witnessInfo
|
|
|
- .map(
|
|
|
- (w: any) =>
|
|
|
- `姓名: ${w.name || ''} 身份证件号码: ${w.id || ''} 联系电话: ${w.phone || ''}\n单位或住址: ${w.address || ''}`
|
|
|
- )
|
|
|
- .join('\n\n')
|
|
|
- : '';
|
|
|
-
|
|
|
- return `${header}\n${items}\n${extractUsers}${witnesses ? '\n\n' + witnesses : ''}`.trim();
|
|
|
-};
|
|
|
+// 旧的文本格式化逻辑已由组件渲染替代,移除无用函数。
|
|
|
|
|
|
const extractionList = ref<{ id?: number; title: string; content: string }[]>([]);
|
|
|
const extractionRawList = ref<any[]>([]);
|
|
|
@@ -945,7 +938,20 @@ const currentAlbum = computed(() => albumList.value[selectedAlbumIndex.value]);
|
|
|
const selectAlbum = (idx: number) => (selectedAlbumIndex.value = idx);
|
|
|
const openAlbumViewer = (index: number) => {
|
|
|
const list = currentAlbum.value?.images || [];
|
|
|
- viewerUrls.value = list.map((i) => i.url);
|
|
|
+ const toOffline = (raw: string) => {
|
|
|
+ if (!raw) return '';
|
|
|
+ const httpHost = /^https?:\/\/[^/]+/i;
|
|
|
+ if (httpHost.test(raw)) return '.' + raw.replace(httpHost, '');
|
|
|
+ if (raw.startsWith('/')) return '.' + raw;
|
|
|
+ if (raw.startsWith('./')) return raw;
|
|
|
+ return './' + raw;
|
|
|
+ };
|
|
|
+ viewerUrls.value = list
|
|
|
+ .map((i) => {
|
|
|
+ const raw = i?.url || '';
|
|
|
+ return isOfflineMode() ? toOffline(String(raw)) : raw;
|
|
|
+ })
|
|
|
+ .filter((u) => !!u);
|
|
|
viewerIndex.value = index;
|
|
|
showViewer.value = true;
|
|
|
};
|