newCaseFile.vue 24 KB

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