newCaseFile.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. <template>
  2. <!-- <com-head
  3. :options="options"
  4. v-model="currentTypeId"
  5. notContent
  6. v-if="options.length"
  7. /> -->
  8. <div class="new-body-layer body-layer">
  9. <template v-if="currentTypeId === 2">
  10. <Photos :caseId="caseId" :title="caseInfoData?.caseTitle || ''" />
  11. </template>
  12. <template v-else-if="currentTypeId === 3">
  13. <Records :caseId="caseId" :title="caseInfoData?.caseTitle || ''" />
  14. </template>
  15. <template v-else-if="currentTypeId === 4">
  16. <Manifest :caseId="caseId" :title="caseInfoData?.caseTitle || ''" />
  17. </template>
  18. <template v-else>
  19. <div class="body-head details-head">
  20. <h3 style="visibility: hidden">绘图管理</h3>
  21. <div>
  22. <template v-if="isDraw">
  23. <!-- <el-button type="primary" @click="gotoDraw(BoardType.map, -1)">
  24. 创建{{ BoardTypeDesc[BoardType.map] }}
  25. </el-button> -->
  26. <el-button type="primary" @click="refresh">
  27. 刷新
  28. </el-button>
  29. <el-button type="primary" @click="openMapDialog">
  30. 创建{{ BoardTypeDesc[BoardType.map] }}
  31. </el-button>
  32. <!-- <el-button type="primary" @click="gotoDraw(BoardType.scene, -1)">
  33. 创建{{ BoardTypeDesc[BoardType.scene] }}
  34. </el-button> -->
  35. <el-button type="primary" @click="openOverView()">
  36. 创建{{ BoardTypeDesc[BoardType.scene] }}
  37. </el-button>
  38. </template>
  39. <el-button type="primary" @click="addCaseFileHandler">
  40. 上传
  41. </el-button>
  42. </div>
  43. </div>
  44. <el-table
  45. v-if="currentTypeId === 6"
  46. :data="files"
  47. class="table-list"
  48. tooltip-effect="dark"
  49. style="width: 100%"
  50. size="large"
  51. >
  52. <el-table-column label="序号" width="100" v-slot:default="{ $index }">
  53. <span style="text-align: center">
  54. {{ $index + 1 }}
  55. </span>
  56. </el-table-column>
  57. <el-table-column
  58. label="名称"
  59. v-slot:default="{ row }: { row: CaseFile }"
  60. >
  61. <span v-if="!inputCaseTitles.includes(row)">
  62. {{ row.filesTitle }}
  63. <el-icon class="edit-title" @click="startEdit(row)">
  64. <EditPen />
  65. </el-icon>
  66. </span>
  67. <template v-else>
  68. <ElInput
  69. v-model="row.filesTitle"
  70. placeholder="请输入文件名"
  71. @blur="updateFileTitle(row)"
  72. :maxlength="50"
  73. style="width: 280px"
  74. :ref="(el) => setInputRef(row.filesId, el as any)"
  75. />
  76. </template>
  77. </el-table-column>
  78. <el-table-column label="创建时间" prop="createTime"></el-table-column>
  79. <el-table-column
  80. label="操作"
  81. v-slot:default="{ row }: { row: CaseFile }"
  82. >
  83. <span class="oper-span" @click="query(row)"> 查看 </span>
  84. <span
  85. class="oper-span"
  86. @click="gotoDraw(row.imgType!, row.filesId)"
  87. v-if="row.imgType !== null"
  88. >
  89. 编辑
  90. </span>
  91. <span class="oper-span delBtn" @click="del(row)"> 删除 </span>
  92. </el-table-column>
  93. </el-table>
  94. <!-- 卡片网格布局 -->
  95. <div class="file-grid-container" v-if="currentTypeId === 1 && files.length">
  96. <div
  97. class="file-card"
  98. v-for="(file, index) in files"
  99. :key="file.filesId"
  100. >
  101. <!-- 卡片图片容器 -->
  102. <div class="card-image-container">
  103. <el-image
  104. ref="imageRef"
  105. :src="file.filesUrl"
  106. :preview-teleported="true"
  107. class="card-image"
  108. >
  109. <template #error>
  110. <div class="image-error">
  111. <el-icon size="40" color="#c0c4cc">
  112. <Document />
  113. </el-icon>
  114. </div>
  115. </template>
  116. </el-image>
  117. <!-- 悬浮操作按钮 -->
  118. <div class="card-overlay">
  119. <div class="card-actions">
  120. <el-button
  121. class="card-overlay-btn"
  122. size="default"
  123. circle
  124. @click.stop="previewImage(index)"
  125. title="查看"
  126. >
  127. <el-icon :size="20"><ZoomIn /></el-icon>
  128. </el-button>
  129. <!-- 编辑按钮:old 类型不显示,其他类型显示 -->
  130. <el-button
  131. class="card-overlay-btn"
  132. size="default"
  133. circle
  134. @click.stop="handleEdit(file)"
  135. v-if="file.type !== 'old'"
  136. title="编辑"
  137. >
  138. <el-icon :size="20"><EditPen /></el-icon>
  139. </el-button>
  140. <!-- 对于 old 类型,保留原来的编辑逻辑 -->
  141. <!-- <el-button
  142. class="card-overlay-btn"
  143. size="default"
  144. circle
  145. @click.stop="gotoDraw(file.imgType!, file.filesId)"
  146. v-if="file.type === 'old' && file.imgType !== null"
  147. title="编辑"
  148. >
  149. <el-icon :size="20"><Edit /></el-icon>
  150. </el-button> -->
  151. <el-button
  152. class="card-overlay-btn"
  153. size="default"
  154. circle
  155. @click.stop="del(file)"
  156. title="删除"
  157. >
  158. <el-icon :size="20"><Delete /></el-icon>
  159. </el-button>
  160. </div>
  161. </div>
  162. </div>
  163. <!-- 卡片底部:文件名 -->
  164. <div class="card-footer">
  165. <div class="file-title">
  166. <span v-if="!inputCaseTitles.includes(file)" :title="file.filesTitle" class="title-text">
  167. {{ file.filesTitle }}
  168. <el-icon color="#999" class="edit-title" @click="startEdit(file)">
  169. <EditPen />
  170. </el-icon>
  171. </span>
  172. <template v-else>
  173. <ElInput
  174. v-model="file.filesTitle"
  175. placeholder="请输入文件名"
  176. @blur="updateFileTitle(file)"
  177. :maxlength="50"
  178. size="default"
  179. class="edit-input"
  180. :ref="(el) => setInputRef(file.filesId, el as any)"
  181. />
  182. </template>
  183. </div>
  184. </div>
  185. <el-image-viewer
  186. v-if="showPreview"
  187. :url-list="srcList"
  188. :initial-index="currentPreviewIndex"
  189. @close="showPreview = false"
  190. />
  191. </div>
  192. </div>
  193. <div class="file-container-nodata" v-else>
  194. <img src="@/assets/image/empty__empty.png" alt="暂无数据" />
  195. <div>暂无数据</div>
  196. </div>
  197. <!-- 地图选择弹窗 -->
  198. <CreatMap
  199. v-model="showMapDialog"
  200. :caseId="caseId"
  201. @confirm="handleMapConfirm"
  202. />
  203. </template>
  204. </div>
  205. </template>
  206. <script setup lang="ts">
  207. import comHead from "@/components/head/index.vue";
  208. import { confirm } from "@/helper/message";
  209. import { RouteName, router } from "@/router";
  210. import { FileDrawType, BoardTypeDesc } from "@/constant/caseFile";
  211. import { computed, onMounted, onUnmounted, ref, watchEffect, nextTick } from "vue";
  212. import { addCaseFile } from "./quisk";
  213. import { title, desc } from "@/store/system";
  214. import {
  215. CaseFile,
  216. CaseFileType,
  217. getCaseFileTypes,
  218. getCaseFiles,
  219. delCaseFile,
  220. BoardType,
  221. } from "@/store/caseFile";
  222. import { getCaseInfo, updateCaseInfo, getCaseTabulationList, getCaseOverviewList, updateCaseTabulation, updateCaseOverview, delCaseTabulation, delCaseOverview } from "@/store/case";
  223. import { appConstant } from "@/app";
  224. import { ElIcon, ElInput, ElMessage, ElImage, ElButton } from "element-plus";
  225. import { EditPen, Document, View, Edit, Delete } from "@element-plus/icons-vue";
  226. import Photos from "./photos/index.vue";
  227. import Records from "./records/index.vue";
  228. import Manifest from "./records/manifest.vue";
  229. import CreatMap from "./drawMap/creatMap.vue";
  230. import { user } from "@/store/user";
  231. // 根基app打开不同地址
  232. const appId = import.meta.env.VITE_APP_APP || 'fire'
  233. const url = 'http://test-mix3d.4dkankan.com'
  234. const props = defineProps<{
  235. caseId?: number;
  236. currentMenuKey?: string;
  237. }>();
  238. const caseId = computed(() => {
  239. if (props.caseId) {
  240. return props.caseId;
  241. }
  242. const caseId = router.currentRoute.value.params.caseId;
  243. if (caseId) {
  244. return Number(caseId);
  245. }
  246. });
  247. const caseInfoData = ref<any>();
  248. const inputCaseTitles = ref<CaseFile[]>([]);
  249. const inputRefs = ref<Record<number, InstanceType<typeof ElInput> | null>>({});
  250. const setInputRef = (filesId: number, el: InstanceType<typeof ElInput> | null) => {
  251. if (filesId == null) return;
  252. inputRefs.value[filesId] = el;
  253. };
  254. const startEdit = async (file: CaseFile) => {
  255. if (!inputCaseTitles.value.includes(file)) {
  256. inputCaseTitles.value.push(file);
  257. }
  258. await nextTick();
  259. const target = inputRefs.value[file.filesId!];
  260. if (target && typeof (target as any).focus === 'function') {
  261. (target as any).focus();
  262. }
  263. };
  264. // 处理标题输入事件
  265. const handleTitleInput = (file: CaseFile, value: string) => {
  266. file.filesTitle = value;
  267. };
  268. const updateFileTitle = async (caseFile: CaseFile) => {
  269. // 根据文件类型检查不同的标题字段
  270. const title = caseFile.filesTitle;
  271. if (!title || !title.trim()) {
  272. ElMessage.error("标题不能为空!");
  273. return;
  274. }
  275. try {
  276. // 根据文件类型调用不同的更新接口
  277. await updateCaseInfo(caseFile);
  278. // if (caseFile.type === 'old') {
  279. // await updateCaseInfo(caseFile);
  280. // }
  281. // else if (caseFile.type === 'tabulation') {
  282. // // updateCaseTabulation 参数:id, caseId, store, viewport, cover, paperKey, overviewId, isAutoGen, listCover, mapUrl, high, width
  283. // await updateCaseTabulation({
  284. // id: caseFile.id,
  285. // caseId: caseFile.caseId,
  286. // store: caseFile.store,
  287. // viewport: caseFile.viewport,
  288. // cover: caseFile.cover,
  289. // paperKey: caseFile.paperKey,
  290. // overviewId: caseFile.overviewId,
  291. // isAutoGen: caseFile.isAutoGen,
  292. // listCover: caseFile.listCover,
  293. // mapUrl: caseFile.mapUrl,
  294. // high: caseFile.high,
  295. // width: caseFile.width,
  296. // title: title // 使用最新输入的 title
  297. // });
  298. // } else if (caseFile.type === 'overview') {
  299. // // updateCaseOverview 参数:id, caseId, store, title, cover, mapUrl, listCover, high, width, kankanCover
  300. // await updateCaseOverview({
  301. // id: caseFile.id,
  302. // caseId: caseFile.caseId,
  303. // store: caseFile.store,
  304. // title: title, // 使用最新输入的 title
  305. // cover: caseFile.cover,
  306. // mapUrl: caseFile.mapUrl,
  307. // listCover: caseFile.listCover,
  308. // high: caseFile.high,
  309. // width: caseFile.width,
  310. // kankanCover: caseFile.kankanCover
  311. // });
  312. // }
  313. inputCaseTitles.value = inputCaseTitles.value.filter(
  314. (item) => item !== caseFile
  315. );
  316. // 更新成功后刷新列表
  317. refresh();
  318. // ElMessage.success("更新成功!");
  319. } catch (error) {
  320. console.error('更新失败:', error);
  321. ElMessage.error("更新失败!");
  322. }
  323. };
  324. const currentTypeId = ref<number>();
  325. const types = ref<CaseFileType[]>([]);
  326. const options = computed(() =>
  327. types.value.map((item) => ({
  328. name: item.filesTypeName,
  329. value: item.filesTypeId,
  330. }))
  331. );
  332. // 根据currentMenuKey设置currentTypeId
  333. watchEffect(() => {
  334. if (props.currentMenuKey) {
  335. const MenuTypeEnum = {
  336. drawing: 1,
  337. photo: 2,
  338. record: 3,
  339. list: 4,
  340. other: 6
  341. };
  342. currentTypeId.value = MenuTypeEnum[props.currentMenuKey] || Number(props.currentMenuKey);
  343. }
  344. });
  345. const isDraw = computed(() => currentTypeId.value === FileDrawType);
  346. type CaseFileEx = CaseFile & {
  347. type?: 'old' | 'tabulation' | 'overview'
  348. tabulationId?: number
  349. overviewId?: number
  350. id?: number
  351. };
  352. const files = ref<CaseFileEx[]>([]);
  353. // 计算预览图片列表
  354. const srcList = computed(() => {
  355. return files.value.map(file => {
  356. // 根据文件类型返回对应的图片URL
  357. return file.filesUrl;
  358. });
  359. });
  360. // 预览图片方法
  361. const imageRef = ref()
  362. const showPreview = ref(false)
  363. const currentPreviewIndex = ref(0)
  364. const previewImage = (index: number) => {
  365. console.log(index)
  366. const file = files.value[index];
  367. // 设置当前预览图片的索引
  368. currentPreviewIndex.value = index;
  369. // 根据文件类型处理查看逻辑
  370. if (file.type === 'old') {
  371. // old 类型使用原来的查看逻辑
  372. const ext = file.filesUrl
  373. .substring(file.filesUrl.lastIndexOf("."))
  374. .toLocaleLowerCase();
  375. // 如果是图片文件,让 el-image 的预览功能自动处理
  376. const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
  377. if (imageExts.includes(ext)) {
  378. showPreview.value = true
  379. return
  380. }
  381. if ([".raw", ".dcm"].includes(ext)) {
  382. window.open(
  383. `/${appId}/xfile-viewer/index.html?file=${file.filesUrl}&name=${file.filesTitle}&time=` +
  384. Date.now()
  385. );
  386. } else {
  387. window.open(file.filesUrl + "?time=" + Date.now());
  388. }
  389. } else {
  390. // tabulation 和 overview 类型的查看逻辑
  391. if (file.filesUrl) {
  392. // 如果有封面图,显示预览
  393. showPreview.value = true
  394. } else {
  395. // 否则直接打开文件
  396. window.open(file.filesUrl + "?time=" + Date.now());
  397. }
  398. }
  399. };
  400. const refresh = async () => {
  401. try {
  402. // 并行调用三个接口
  403. const [caseFilesRes] = await Promise.all([
  404. // getCaseTabulationList(caseId.value!),
  405. // getCaseOverviewList(caseId.value!),
  406. getCaseFiles({
  407. caseId: caseId.value!,
  408. filesTypeId: currentTypeId.value,
  409. })
  410. ]);
  411. // 提取数据并为每种类型添加标记
  412. // let tabulationList = (tabulationRes?.data || []).map(item => ({
  413. // ...item,
  414. // title: item.title || '方位图',
  415. // type: 'tabulation' as const
  416. // }));
  417. // // 方位图需要清除封面图为空的数据
  418. // tabulationList = tabulationList.filter(item => item.listCover !== '');
  419. // const overviewList = (overviewRes?.data || []).map(item => ({
  420. // ...item,
  421. // title: item.title || '平面图',
  422. // type: 'overview' as const
  423. // }));
  424. const caseFiles = (caseFilesRes || []).map((item: any) => ({
  425. ...item,
  426. type: (item.tabulationId && item.overviewId)
  427. ? ('overview' as const)
  428. : item.tabulationId
  429. ? ('tabulation' as const)
  430. : ('old' as const)
  431. })) as CaseFileEx[];
  432. files.value = [...caseFiles];
  433. } catch (error) {
  434. console.error('获取文件列表失败:', error);
  435. files.value = [];
  436. }
  437. };
  438. watchEffect(() => caseId.value && currentTypeId.value && refresh());
  439. const query = (file: CaseFile) => {
  440. const ext = file.filesUrl
  441. .substring(file.filesUrl.lastIndexOf("."))
  442. .toLocaleLowerCase();
  443. const appId = import.meta.env.VITE_APP_APP ||'fire'
  444. if ([".raw", ".dcm"].includes(ext)) {
  445. window.open(
  446. `/${appId}/xfile-viewer/index.html?file=${file.filesUrl}&name=${file.filesTitle}&time=` +
  447. Date.now()
  448. );
  449. } else {
  450. window.open(file.filesUrl + "?time=" + Date.now());
  451. }
  452. };
  453. const del = async (file: CaseFile) => {
  454. if (await confirm("确定要删除此数据?")) {
  455. try {
  456. // 根据文件类型调用不同的删除接口
  457. await delCaseFile({ caseId: caseId.value!, filesId: file.filesId });
  458. // if (file.type === 'old') {
  459. // // old 类型的删除逻辑不变
  460. // await delCaseFile({ caseId: caseId.value!, filesId: file.filesId });
  461. // } else if (file.type === 'tabulation') {
  462. // // tabulation 类型调用 /fusion/caseTabulation/del
  463. // await delCaseTabulation({ id: file.id! });
  464. // } else if (file.type === 'overview') {
  465. // // overview 类型调用 /fusion/caseOverview/del
  466. // await delCaseOverview({ id: file.id! });
  467. // }
  468. refresh();
  469. ElMessage.success("删除成功!");
  470. } catch (error) {
  471. console.error('删除失败:', error);
  472. ElMessage.error("删除失败!");
  473. }
  474. }
  475. };
  476. const addCaseFileHandler = async () => {
  477. await addCaseFile({ caseId: caseId.value!, fileType: currentTypeId.value! });
  478. refresh();
  479. };
  480. const gotoDraw = (type: BoardType, id: number) => {
  481. router.push({
  482. name: RouteName.drawCaseFile,
  483. params: { caseId: caseId.value!, type, id },
  484. });
  485. };
  486. // 处理不同类型的编辑逻辑
  487. const handleEdit = (file: CaseFileEx) => {
  488. if (file.type === 'tabulation') {
  489. // tabulation 类型的编辑链接
  490. if(appId === 'fire'){
  491. window.open(`${url}/draw/fire/index.html#/tabulation?caseId=${caseId.value}&tabulationId=${file.tabulationId}&token=${user.value.token}`, '_blank');
  492. } else if(appId === 'criminal'){
  493. window.open(`${url}/draw/criminal/index.html#/tabulation?caseId=${caseId.value}&tabulationId=${file.tabulationId}&token=${user.value.token}`, '_blank');
  494. } else if(appId === 'cjzfire'){
  495. window.open(`${url}/draw/cjzfire/index.html#/tabulation?caseId=${caseId.value}&tabulationId=${file.tabulationId}&token=${user.value.token}`, '_blank');
  496. } else if(appId === 'xmfire'){
  497. window.open(`${url}/draw/xmfire/index.html#/tabulation?caseId=${caseId.value}&tabulationId=${file.tabulationId}&token=${user.value.token}`, '_blank');
  498. } else{
  499. window.open(`${url}/draw/fire/index.html#/tabulation?caseId=${caseId.value}&tabulationId=${file.tabulationId}&token=${user.value.token}`, '_blank');
  500. }
  501. } else if (file.type === 'overview') {
  502. // overview 类型的编辑链接
  503. if(appId === 'fire'){
  504. window.open(`${url}/draw/fire/index.html#/overview?caseId=${caseId.value!}&overviewId=${file.overviewId}&token=${user.value.token}`, '_blank');
  505. } else if(appId === 'criminal'){
  506. window.open(`${url}/draw/criminal/index.html#/overview?caseId=${caseId.value!}&overviewId=${file.overviewId}&token=${user.value.token}`, '_blank');
  507. } else if(appId === 'cjzfire'){
  508. window.open(`${url}/draw/cjzfire/index.html#/overview?caseId=${caseId.value!}&overviewId=${file.overviewId}&token=${user.value.token}`, '_blank');
  509. } else if(appId === 'xmfire'){
  510. window.open(`${url}/draw/xmfire/index.html#/overview?caseId=${caseId.value!}&overviewId=${file.overviewId}&token=${user.value.token}`, '_blank');
  511. } else{
  512. window.open(`${url}/draw/fire/index.html#/overview?caseId=${caseId.value!}&overviewId=${file.overviewId}&token=${user.value.token}`, '_blank');
  513. }
  514. }
  515. };
  516. // 地图弹窗相关
  517. const showMapDialog = ref(false)
  518. // 打开地图选择弹窗,新版本地图选择
  519. const openMapDialog = () => {
  520. showMapDialog.value = true
  521. }
  522. // 创建现场图
  523. const openOverView = () => {
  524. // let avtUrl = {
  525. // criminal: `/criminal/criminal.ico`,
  526. // fire: `/fire/fire.ico`,
  527. // cjzfire: `/cjzfire/cjzfire.ico`,
  528. // }
  529. console.log('appId', appId)
  530. if(appId === 'fire'){
  531. window.open(`${url}/draw/fire/index.html#/overview?caseId=${caseId.value!}&token=${user.value.token}`, '_blank')
  532. } else if(appId === 'criminal'){
  533. window.open(`${url}/draw/criminal/index.html#/overview?caseId=${caseId.value!}&token=${user.value.token}`, '_blank')
  534. } else if(appId === 'cjzfire'){
  535. window.open(`${url}/draw/cjzfire/index.html#/overview?caseId=${caseId.value!}&token=${user.value.token}`, '_blank')
  536. } else if(appId === 'xmfire'){
  537. window.open(`${url}/draw/xmfire/index.html#/overview?caseId=${caseId.value!}&token=${user.value.token}`, '_blank')
  538. } else{
  539. window.open(`${url}/draw/fire/index.html#/overview?caseId=${caseId.value!}&token=${user.value.token}`, '_blank')
  540. }
  541. }
  542. // 处理地图选择确认
  543. const handleMapConfirm = async (location: any) => {
  544. console.log('选择的地图位置:', location)
  545. // 这里可以将位置信息保存到案件中,或者创建地图绘图
  546. try {
  547. // 可以调用相关API保存位置信息
  548. // 或者直接跳转到绘图页面
  549. await router.push({
  550. name: RouteName.drawCaseFile,
  551. params: {
  552. caseId: caseId.value!,
  553. type: BoardType.map,
  554. id: -1
  555. },
  556. query: {
  557. location: JSON.stringify(location)
  558. }
  559. })
  560. } catch (error) {
  561. console.error('处理地图位置失败:', error)
  562. }
  563. }
  564. onMounted(async () => {
  565. try {
  566. types.value = await getCaseFileTypes();
  567. // 如果有传入currentMenuKey,则使用它,否则使用默认值
  568. if (props.currentMenuKey) {
  569. const MenuTypeEnum = {
  570. drawing: 1,
  571. photo: 2,
  572. record: 3,
  573. list: 4,
  574. other: 6
  575. };
  576. currentTypeId.value = MenuTypeEnum[props.currentMenuKey] || Number(props.currentMenuKey);
  577. } else {
  578. currentTypeId.value = types.value[0].filesTypeId;
  579. }
  580. // 确保在获取案件信息之前已经有有效的 caseId
  581. if (caseId.value) {
  582. const caseInfo = await getCaseInfo(caseId.value);
  583. if (caseInfo) {
  584. caseInfoData.value = caseInfo;
  585. // title.value = caseInfo.caseTitle + " | 卷宗管理";
  586. // desc.value = "";
  587. } else {
  588. console.error("该案件不存在!");
  589. throw "该案件不存在!";
  590. }
  591. } else {
  592. console.error("案件ID不存在!");
  593. throw "案件ID不存在!";
  594. }
  595. } catch (error) {
  596. console.error("加载案件信息失败:", error);
  597. // debugger;
  598. //TODO 由于没有登录状态可以判断或hook插入,只能延时进入no-case router当前的router
  599. setTimeout(() => {
  600. console.log("current-router", router.currentRoute.value.name);
  601. if (router.currentRoute.value.name !== "login") {
  602. router.replace({ name: RouteName.noCase });
  603. }
  604. }, 1000);
  605. }
  606. });
  607. onUnmounted(() => {
  608. title.value = appConstant.title;
  609. desc.value = appConstant.desc;
  610. });
  611. </script>
  612. <style scoped lang="scss">
  613. .new-body-layer {
  614. background: transparent;
  615. padding-left: 0;
  616. height: calc(100% - 10px);
  617. :deep(.photo) {
  618. .left{
  619. padding-left: 24px;
  620. }
  621. .my-photo-upload{
  622. text-align: left;
  623. }
  624. }
  625. :deep(.records) {
  626. padding-top: 0;
  627. }
  628. .details-head{
  629. height: 56px;
  630. align-items: flex-start;
  631. }
  632. }
  633. .edit-title {
  634. cursor: pointer;
  635. margin-left: 10px;
  636. }
  637. // 卡片网格布局样式
  638. .file-grid-container {
  639. display: grid;
  640. grid-template-columns: repeat(auto-fill, 387px);
  641. gap: 22px;
  642. padding: 16px 0;
  643. }
  644. // 无数据
  645. .file-container-nodata{
  646. margin-top: 14%;
  647. flex-direction: column;
  648. color: rgba(0, 0, 0, 0.25);
  649. img{
  650. width: 128px;
  651. height: 128px;
  652. }
  653. }
  654. .file-card {
  655. background: #ffffff;
  656. // transition: all 0.3s ease;
  657. width: 387px;
  658. height: 303px;
  659. margin-left: 10px;
  660. // display: flex;
  661. // flex-direction: column;
  662. .card-image-container{
  663. &:hover {
  664. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  665. // transform: translateY(-2px);
  666. .card-overlay {
  667. opacity: 1;
  668. }
  669. }
  670. }
  671. :deep(.el-image-viewer__canvas){
  672. background-color: #000;
  673. }
  674. }
  675. .card-image-container {
  676. position: relative;
  677. // flex: 1;
  678. height: 280px;
  679. // overflow: hidden;
  680. border: none;
  681. border-radius: 8px;
  682. box-shadow: 0 0 12px rgba(0,0,0,.12);
  683. }
  684. .card-image {
  685. width: 100%;
  686. height: 100%;
  687. cursor: pointer;
  688. }
  689. .image-error {
  690. width: 100%;
  691. height: 100%;
  692. display: flex;
  693. align-items: center;
  694. justify-content: center;
  695. background: #f5f7fa;
  696. }
  697. .card-overlay {
  698. position: absolute;
  699. top: 0;
  700. left: 0;
  701. right: 0;
  702. bottom: 0;
  703. background: rgba(0, 0, 0, 0.4);
  704. display: flex;
  705. align-items: center;
  706. justify-content: center;
  707. opacity: 0;
  708. transition: opacity 0.3s ease;
  709. }
  710. .card-actions {
  711. display: flex;
  712. gap: 12px;
  713. .card-overlay-btn{
  714. width: 20px;
  715. background: transparent;
  716. border: none;
  717. color: #F2F2F2;
  718. padding: 0;
  719. }
  720. }
  721. .card-footer {
  722. padding: 12px 0;
  723. background: #ffffff;
  724. }
  725. .file-title {
  726. position: relative;
  727. width: 100%;
  728. text-align: left;
  729. .title-text {
  730. display: inline-block;
  731. width: 90%;
  732. font-size: 14px;
  733. font-weight: 500;
  734. color: #303133;
  735. text-align: left;
  736. display: flex;
  737. align-items: center;
  738. word-break: break-all;
  739. overflow: hidden;
  740. white-space: nowrap;
  741. text-overflow: ellipsis;
  742. }
  743. // .edit-title{
  744. // display: none;
  745. // position: absolute;
  746. // right: 0;
  747. // }
  748. .edit-input {
  749. :deep(.el-input__wrapper) {
  750. height: 20px;
  751. }
  752. :deep(.el-input-group__append) {
  753. .el-button {
  754. height: 30px;
  755. }
  756. }
  757. }
  758. }
  759. .file-title:hover{
  760. .edit-title{
  761. display: inline-block;
  762. }
  763. }
  764. .file-time {
  765. font-size: 12px;
  766. color: #909399;
  767. margin-top: 4px;
  768. }
  769. // 响应式设计
  770. @media (max-width: 1200px) {
  771. .file-grid-container {
  772. grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  773. }
  774. }
  775. @media (max-width: 768px) {
  776. .file-grid-container {
  777. grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  778. gap: 12px;
  779. }
  780. .file-card {
  781. height: 240px;
  782. }
  783. .card-footer {
  784. padding: 8px 0;
  785. }
  786. }
  787. </style>