1
0

index.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. <template>
  2. <div class="records">
  3. <div class="header" style="flex-direction: row-reverse">
  4. <el-button @click="backPageHandler">返回</el-button>
  5. <el-button style="margin: 0px 10px" type="primary" @click="handleSave"
  6. >保存</el-button
  7. >
  8. <el-button :disabled="isDisableExport" @click="handleExport"
  9. >导出</el-button
  10. >
  11. </div>
  12. <h3 class="title">现 场 勘 验 笔 录</h3>
  13. <div class="content">
  14. <div class="line" style="flex-direction: row-reverse">
  15. <el-input
  16. class="input"
  17. v-model="data.inquestNum"
  18. placeholder=""
  19. style="width: 280px"
  20. />
  21. <span>现场勘验号:</span>
  22. </div>
  23. <div class="line">
  24. <span>现场勘验单位:</span>
  25. <el-input
  26. class="input"
  27. v-model="data.deptName"
  28. placeholder=""
  29. style="width: 100%"
  30. />
  31. </div>
  32. <div class="line">
  33. <span>指派/报告单位:</span>
  34. <el-input
  35. class="input"
  36. v-model="data.reportDept"
  37. placeholder=""
  38. style="width: 100%"
  39. />
  40. </div>
  41. <div class="line">
  42. <span>勘验时间: &nbsp; </span>
  43. <div>
  44. <el-date-picker
  45. class="input"
  46. v-model="data.inquestTime"
  47. type="datetime"
  48. placeholder="勘验时间"
  49. value-format="YYYY-MM-DD HH:mm:ss"
  50. style="width: 200px"
  51. />
  52. </div>
  53. </div>
  54. <div class="textarea">
  55. <span>勘验事由: </span>
  56. <el-input
  57. type="textarea"
  58. :rows="6"
  59. v-model="data.inquestResource"
  60. placeholder="报警人:xxx(性别:xxx 电话:xxx)报警称:xxx发生一起:xxx案,现场需勘察。接报后技术科科长:xxx带领技术员:xxx、法医:xxx立即赶赴现场进行勘察."
  61. style="width: 100%"
  62. />
  63. </div>
  64. <div class="line">
  65. <span>现场勘验时间: &nbsp; </span>
  66. <div>
  67. <el-date-picker
  68. class="input"
  69. v-model="data.times"
  70. type="datetimerange"
  71. range-separator="至"
  72. start-placeholder="现场勘验开始时间"
  73. end-placeholder="现场勘验结束时间"
  74. />
  75. </div>
  76. </div>
  77. <div class="line">
  78. <span>现场地点:</span>
  79. <el-input
  80. class="input"
  81. type="text"
  82. v-model="data.address"
  83. placeholder=""
  84. style="width: 100%"
  85. />
  86. </div>
  87. <div class="line">
  88. <span>现场保护情况:</span>
  89. <el-input
  90. class="input"
  91. type="text"
  92. v-model="data.protectionSituation"
  93. placeholder=""
  94. style="width: 100%"
  95. />
  96. </div>
  97. <div class="line">
  98. <span>现场保护人: &nbsp;&nbsp; &nbsp;</span>
  99. <span>姓名</span>
  100. <!-- 单位 XX派出所 职务 一级警长 -->
  101. <el-input
  102. class="input"
  103. type="text"
  104. v-model="data.protector.name"
  105. placeholder=""
  106. style="width: 180px"
  107. />
  108. <span>单位</span>
  109. <el-input
  110. class="input"
  111. type="text"
  112. v-model="data.protector.unit"
  113. placeholder=""
  114. style="width: 200px"
  115. />
  116. <span>职务</span>
  117. <el-input
  118. class="input"
  119. type="text"
  120. v-model="data.protector.job"
  121. placeholder=""
  122. style="width: 200px"
  123. />
  124. </div>
  125. <!-- protectionMeasures -->
  126. <div class="line">
  127. <span>保护措施:&nbsp; </span>
  128. <el-checkbox-group v-model="data.protectionMeasures">
  129. <el-checkbox :value="0" label="专人看护现场,防止他人进入" />
  130. <el-checkbox :value="1" checked label="设立警戒带,划定禁行区域" />
  131. <el-checkbox :value="2" label="其他措施" />
  132. </el-checkbox-group>
  133. </div>
  134. <div class="line">
  135. <span>现场情况: &nbsp; </span>
  136. <el-checkbox-group v-model="data.situation">
  137. <el-checkbox :value="0" label="原始现场" />
  138. <el-checkbox :value="1" checked label="变动现场" />
  139. </el-checkbox-group>
  140. </div>
  141. <!-- changeReason -->
  142. <div class="line">
  143. <span>变动原因: &nbsp; </span>
  144. <el-checkbox-group v-model="data.changeReason">
  145. <el-checkbox
  146. v-for="reason in ChangeReasonType"
  147. :value="reason.id"
  148. :label="reason.name"
  149. >
  150. </el-checkbox>
  151. <!-- <el-checkbox :value="0" label="事主进入" />
  152. <el-checkbox :value="1" label="报案人进入" />
  153. <el-checkbox :value="2" label="其他" /> -->
  154. </el-checkbox-group>
  155. <el-input
  156. class="input"
  157. v-model="data.changeReasonOtherValue"
  158. :disabled="!data.changeReason.includes(2)"
  159. style="margin-left: 20px; width: 200px"
  160. />
  161. </div>
  162. <div class="line">
  163. <span>天气: &nbsp; </span>
  164. <el-checkbox-group v-model="data.weatherInfo.type">
  165. <el-checkbox :value="0" label="阴" />
  166. <el-checkbox :value="1" label="晴" />
  167. <el-checkbox :value="2" label="雨" />
  168. <el-checkbox :value="3" label="雾" />
  169. </el-checkbox-group>
  170. <span style="margin-left: 20px; font-size: 12px">温度: &nbsp;</span>
  171. <el-input
  172. class="input"
  173. v-model="data.weatherInfo.temperature"
  174. style="width: 80px"
  175. /><span>℃</span>
  176. <span style="margin-left: 20px; font-size: 12px">湿度: &nbsp;</span>
  177. <el-input
  178. class="input"
  179. v-model="data.weatherInfo.humidity"
  180. style="width: 80px"
  181. /><span>%</span>
  182. <span style="margin-left: 20px; font-size: 12px">风向: &nbsp;</span>
  183. <el-input
  184. class="input"
  185. v-model="data.weatherInfo.windDirection"
  186. style="width: 80px"
  187. />
  188. </div>
  189. <div class="line">
  190. <span>现场勘验利用的光线: &nbsp; </span>
  191. <el-checkbox-group v-model="data.light">
  192. <el-checkbox :value="0" checked label="自然光" />
  193. <el-checkbox :value="1" checked label="灯光" />
  194. <el-checkbox :value="2" label="特种光" />
  195. </el-checkbox-group>
  196. </div>
  197. <div class="line">
  198. <span>现场勘验指挥人: &nbsp;&nbsp; </span>
  199. <span>姓名</span>
  200. <!-- 单位 XX派出所 职务 一级警长 -->
  201. <el-input
  202. class="input"
  203. type="text"
  204. v-model="data.inquestCommander.name"
  205. placeholder=""
  206. style="width: 180px"
  207. />
  208. <span>单位</span>
  209. <el-input
  210. class="input"
  211. type="text"
  212. v-model="data.inquestCommander.unit"
  213. placeholder=""
  214. style="width: 200px"
  215. />
  216. <span>职务</span>
  217. <el-input
  218. class="input"
  219. type="text"
  220. v-model="data.inquestCommander.job"
  221. placeholder=""
  222. style="width: 200px"
  223. />
  224. </div>
  225. <div class="textarea">
  226. <div>
  227. <span>现场勘验情况 :</span>
  228. <span @click="handleShowAi" style="color:#26559B;cursor: pointer;float: right;font-weight: bold;">AI</span>
  229. </div>
  230. <el-input
  231. type="textarea"
  232. :rows="6"
  233. v-model="data.inquestSituation"
  234. placeholder=""
  235. style="width: 100%"
  236. />
  237. </div>
  238. <div class="line">
  239. <span>现场勘验制图&nbsp; </span>
  240. <el-input-number
  241. class="input"
  242. controls-position="right"
  243. v-model="data.imageNum"
  244. style="width: 130px"
  245. />
  246. <span>张; &nbsp;&nbsp;</span>
  247. <span>照相</span>
  248. <el-input-number
  249. class="input"
  250. controls-position="right"
  251. v-model="data.photographNum"
  252. style="width: 130px"
  253. />
  254. <span>张;&nbsp;&nbsp;</span>
  255. <span>摄像</span>
  256. <el-input-number
  257. class="input"
  258. controls-position="right"
  259. v-model="data.photographyMinNum"
  260. style="width: 130px"
  261. />
  262. <span>分</span>
  263. <el-input-number
  264. class="input"
  265. controls-position="right"
  266. v-model="data.photographySecNum"
  267. style="width: 130px"
  268. />
  269. <span>秒</span>
  270. <span style="margin-left: 10px">录音</span>
  271. <el-input-number
  272. class="input"
  273. controls-position="right"
  274. v-model="data.recordingMinNum"
  275. style="width: 130px"
  276. />
  277. <span>分</span>
  278. <el-input-number
  279. class="input"
  280. controls-position="right"
  281. v-model="data.recordingSecNum"
  282. style="width: 130px"
  283. />
  284. <span>秒</span>
  285. </div>
  286. <div class="line">
  287. 现场勘验记录人员:
  288. <el-button link @click="recorderInfoDialogShow = true"
  289. ><el-icon :size="18"><CirclePlus /> </el-icon>
  290. </el-button>
  291. </div>
  292. <!-- 现场勘验记录人员 -->
  293. <template v-for="(info, index) in data.recorderInfo">
  294. <div class="line info">
  295. <span>{{ info.typeLabel }}: &nbsp;&nbsp; </span>
  296. <span>姓名</span>
  297. <!-- 单位 XX派出所 职务 一级警长 -->
  298. <el-input
  299. class="input"
  300. type="text"
  301. v-model="info.name"
  302. placeholder=""
  303. style="width: 180px"
  304. />
  305. <span>单位</span>
  306. <el-input
  307. class="input"
  308. type="text"
  309. v-model="info.unit"
  310. placeholder=""
  311. style="width: 200px"
  312. />
  313. <span>职务</span>
  314. <el-input
  315. class="input"
  316. type="text"
  317. v-model="info.job"
  318. placeholder=""
  319. style="width: 200px"
  320. />
  321. <el-button
  322. link
  323. class="del-btn"
  324. type="danger"
  325. @click="removeRecorderInfo(index)"
  326. ><el-icon :size="18"><CircleClose /> </el-icon>
  327. </el-button>
  328. </div>
  329. </template>
  330. <div class="line">
  331. 现场勘验人员:
  332. <el-button link @click="addSignatureInfo"
  333. ><el-icon :size="18"><CirclePlus /> </el-icon>
  334. </el-button>
  335. </div>
  336. <template v-for="(sign, index) of data.signatureInfo">
  337. <div class="line info">
  338. <span>本人签名: &nbsp;&nbsp; </span>
  339. <span>_______________ &nbsp;&nbsp;</span>
  340. <span>单位</span>
  341. <el-input
  342. class="input"
  343. type="text"
  344. v-model="sign.unit"
  345. placeholder=""
  346. style="width: 200px"
  347. />
  348. <span>职务</span>
  349. <el-input
  350. class="input"
  351. type="text"
  352. v-model="sign.job"
  353. placeholder=""
  354. style="width: 200px"
  355. />
  356. <el-button
  357. class="del-btn"
  358. link
  359. type="danger"
  360. @click="removeSignatureInfo(index)"
  361. ><el-icon :size="18"><CircleClose /> </el-icon>
  362. </el-button>
  363. </div>
  364. </template>
  365. <div class="line">
  366. 现场勘验见证人:
  367. <el-button link @click="addWitnessInfo"
  368. ><el-icon :size="18"><CirclePlus /> </el-icon>
  369. </el-button>
  370. </div>
  371. <template v-for="(witness, index) of data.witnessInfo">
  372. <div class="line info">
  373. <span>本人签名: &nbsp;&nbsp; </span>
  374. <span>_______________ &nbsp;&nbsp;</span>
  375. <span>性别</span>
  376. <el-select
  377. class="input"
  378. v-model="witness.sex"
  379. placeholder="性别"
  380. style="width: 140px"
  381. >
  382. <el-option :value="0" label="男" />
  383. <el-option :value="1" label="女" />
  384. </el-select>
  385. <span>出生日期</span>
  386. <el-date-picker
  387. class="input"
  388. v-model="witness.birthday"
  389. type="date"
  390. placeholder="出生日期"
  391. style="width: 180px"
  392. />
  393. <!-- <el-input
  394. class="input"
  395. type="text"
  396. v-model="witness.birthday"
  397. placeholder=""
  398. style="width: 200px"
  399. /> -->
  400. <span>住址</span>
  401. <el-input
  402. class="input"
  403. type="text"
  404. v-model="witness.address"
  405. placeholder=""
  406. style="width: 260px"
  407. />
  408. <el-button
  409. link
  410. class="del-btn"
  411. type="danger"
  412. @click="removeWitnessInfo(index)"
  413. ><el-icon :size="18"><CircleClose /> </el-icon>
  414. </el-button>
  415. </div>
  416. </template>
  417. <div class="textarea">
  418. <span>备注:</span>
  419. <el-input
  420. type="textarea"
  421. :rows="6"
  422. v-model="data.remark"
  423. placeholder=""
  424. style="width: 100%"
  425. />
  426. </div>
  427. <div></div>
  428. </div>
  429. <el-dialog
  430. v-model="recorderInfoDialogShow"
  431. title="增加现场勘验记录人员"
  432. width="500"
  433. align-center
  434. @close="recorderInfoDialogSelect = null"
  435. >
  436. <div class="border" style=" width: 500px;
  437. height: 1px;
  438. margin-bottom: 20px;
  439. border-bottom: none;
  440. position: relative;
  441. left: -16px;"></div>
  442. <div style="width: 80%; margin: 30px auto">
  443. <el-select
  444. v-model="recorderInfoDialogSelect"
  445. placeholder="请选择现场勘验记录人员"
  446. size="large"
  447. >
  448. <el-option
  449. v-for="item in recorderInfoType"
  450. :key="item.type"
  451. :label="item.typeLabel"
  452. :value="item.type"
  453. />
  454. </el-select>
  455. </div>
  456. <template #footer>
  457. <div class="dialog-footer">
  458. <el-button type="primary" @click="addRecorderInfo"> 确定 </el-button>
  459. </div>
  460. </template>
  461. </el-dialog>
  462. <el-dialog
  463. v-model="aiImgShow"
  464. title="AI识别平面图"
  465. width="1300px"
  466. align-center
  467. @close="aiImgData.result = null"
  468. >
  469. <div class="border" style=" width: 1300px;
  470. height: 1px;
  471. margin-bottom: 20px;
  472. border-bottom: none;
  473. position: relative;
  474. left: -16px;"></div>
  475. <div class="flex space-x-4 items-center content-center justify-center text-center">
  476. <div class="flex-1" style="width: 80%;">
  477. <el-select
  478. v-model="aiImgData.src"
  479. placeholder="请选择平面图"
  480. size="large"
  481. >
  482. <el-option
  483. v-for="item in aiImgData.list"
  484. :key="item.num"
  485. :label="item.num"
  486. :value="item.urls[0]"
  487. />
  488. </el-select>
  489. <div class="viewImg mt-4 text-center" style="height: 400px; line-height: 400px; border-radius: 0px 0px 0px 0px;
  490. border: 1px solid #D9D9D9;">
  491. <img class="w-full h-full object-cover" v-if="aiImgData.src" :src="aiImgData.src" alt="" />
  492. <span v-else>预览选中的平面图</span>
  493. </div>
  494. </div>
  495. <div class="flex-1 text-center content-start" style="border-radius: 0px 0px 0px 0px;
  496. border: 1px solid #D9D9D9;min-height: 450px">
  497. <span style="line-height: 450px" v-if="aiImgData.loading">思考中</span>
  498. <span style="line-height: 450px" v-else-if="!aiImgData.result">请点击【识别】获取结果</span>
  499. <div class="text-left" style="height: 450px;padding: 10px; overflow: auto;" v-else v-html="aiImgData.result"></div>
  500. </div>
  501. </div>
  502. <template #footer>
  503. <div class="dialog-footer text-center flex">
  504. <div style="width: 50%">
  505. <el-button type="primary" :disabled="!aiImgData.src" @click="handleAI"> 识别 </el-button>
  506. </div>
  507. <div style="width: 50%">
  508. <el-button :disabled="!aiImgData.result" @click="handleCopy"> 复制 </el-button>
  509. </div>
  510. </div>
  511. </template>
  512. </el-dialog>
  513. </div>
  514. </template>
  515. <script setup>
  516. import { onMounted, ref, watch, h, computed } from "vue";
  517. import { reactive } from "vue";
  518. import { router, RouteName } from "@/router";
  519. import {
  520. getCaseInquestInfo,
  521. saveCaseInquestInfo,
  522. exportCaseInquestInfo,
  523. getCaseInquestInfoOld,
  524. getAiByImage,
  525. getFloorList,
  526. } from "@/store/case";
  527. import { ElMessage, ElMessageBox } from "element-plus";
  528. import saveAs from "@/util/file-serve";
  529. import { CirclePlus, CircleClose, MagicStick } from "@element-plus/icons-vue";
  530. import { recorderInfoType, ChangeReasonType } from "./formData.ts";
  531. import { confirm } from "@/helper/message";
  532. import { chat, abort, listModels } from "@/util/ollama";
  533. import { copyTextToClipboard } from "@/util/index";
  534. const props = defineProps({ caseId: Number, title: String });
  535. console.log("router.currentRoute", router.currentRoute.value?.params);
  536. const fileId = computed(() => router.currentRoute.value?.params?.fileId);
  537. const caseId = computed(() => router.currentRoute.value?.params?.caseId);
  538. const isDisableExport = ref(false);
  539. const aiImgShow = ref(false)
  540. const aiImgData = ref({
  541. src: '',
  542. result: ``,
  543. loading: false,
  544. list: [],
  545. })
  546. const data = reactive({
  547. title: "",
  548. inquestNum: "", //现场勘验号
  549. deptName: "", //单位名称
  550. sendDept: "", //发送单位
  551. issuanceCount: "", // 份数
  552. makeTime: "", //制作时间
  553. recorder: "", // 笔录人
  554. issuanceOpinion: "", //签发意见
  555. reportDept: "", //报告单位
  556. times: [], // startTime ,endTime
  557. address: "", // 勘验地址
  558. inquestTime: "", //勘验时间
  559. inquestResource:
  560. "x年x月x日x单位接到报警称;x年x月x日x地点发生一起什么案事件,需要勘验现场, 接通知后,技术员xx,xx前往现场考察", //勘验范围
  561. protector: {
  562. name: "",
  563. unit: "",
  564. job: "",
  565. }, // 现场保护人
  566. protectionSituation: "", // 现场保护情况
  567. situation: [], //现场情况
  568. changeReason: [],
  569. changeReasonOtherValue: "",
  570. protectionMeasures: [], //保护措施
  571. weatherInfo: {
  572. type: [],
  573. temperature: "",
  574. humidity: "",
  575. windDirection: "",
  576. }, //天气情况
  577. light: [], //光线
  578. painter: "",
  579. photographer: "",
  580. inquestCommander: {
  581. name: "",
  582. unit: "",
  583. job: "",
  584. }, //现场勘验指挥人
  585. inquestSituation: "案发现场以XXX小区为中心,东侧为XXX路,西侧是XXX街,北侧为XXX路,南侧是XXX路。", //现场勘验情况
  586. imageNum: 0, //现场勘验制图数量
  587. photographNum: 0, //照相数量
  588. photographyMinNum: 0, //摄影数量
  589. photographySecNum: 0, //摄影数量
  590. recorderInfo: JSON.parse(JSON.stringify(recorderInfoType)),
  591. signatureInfo: [], //现场勘验人员
  592. witnessInfo: [],
  593. remark: "",
  594. });
  595. const signatureInfoNum = 4;
  596. const witnessInfoNum = 2;
  597. const recorderInfoDialogShow = ref(false);
  598. const recorderInfoDialogSelect = ref();
  599. const initInfo = async (inquestFileId) => {
  600. const res = await getCaseInquestInfoOld(inquestFileId || fileId.value);
  601. console.log("initInfo", res);
  602. if (!res.data) {
  603. isDisableExport.value = true;
  604. } else {
  605. isDisableExport.value = false;
  606. }
  607. for (var k in data) {
  608. if (res.data && res.data.hasOwnProperty(k)) {
  609. // console.log("Key is " + k);
  610. if (res.data[k]) {
  611. data[k] = res.data[k];
  612. }
  613. }
  614. }
  615. setTimeout(() => {
  616. initSignatureAndWitInfo();
  617. }, 500);
  618. };
  619. const handleCopy = () => {
  620. copyTextToClipboard(aiImgData.value.result);
  621. ElMessage.success("复制成功!");
  622. }
  623. const handleShowAi = async () => {
  624. const list = await getFloorList(caseId.value)
  625. aiImgData.value.list = list.filter((i) => i.urls && i.urls.length);
  626. aiImgData.value.src = list[0]?.urls[0];
  627. aiImgShow.value = true;
  628. }
  629. //判断是否deepseek
  630. let isThink = ref(false);
  631. let testRegex = /deepseek/;
  632. const handleAI = async () => {
  633. aiImgData.value.loading = true;
  634. let orgin = window.location.origin;
  635. let imageUrl = orgin + aiImgData.value.src
  636. try {
  637. // const res = await getAiByImage({imageUrl: imageUrl})
  638. chat('', '人为什么要吃饭').then(async stream => {
  639. for await (const part of stream) {
  640. // chatHistory.value.at(idx).text += part.message.content;
  641. let tep_mesg = part.message.content;
  642. console.log("isThinktep", tep_mesg);
  643. //判断是否是deepseek模型
  644. // if (testRegex.test(agentInfo.value.model)) {
  645. if (tep_mesg == "\u003c/think\u003e") {
  646. // isThink.value = true;
  647. aiImgData.value.loading = false;
  648. }
  649. if (!aiImgData.value.loading) {
  650. //清除think
  651. if (
  652. tep_mesg == "\u003cthink\u003e" ||
  653. tep_mesg == "\u003c/think\u003e"
  654. ) {
  655. // chatHistory.value.at(idx).think += "";
  656. } else {
  657. console.log("isThinktep_mesg", tep_mesg);
  658. aiImgData.value.result += tep_mesg;
  659. // chatHistory.value.at(idx).think += tep_mesg;
  660. }
  661. //如果结尾标签则停止拼接
  662. if (tep_mesg == "\u003c/think\u003e") {
  663. // isThink.value = false;
  664. }
  665. } else {
  666. // aiImgData.value.result += tep_mesg;
  667. // chatHistory.value.at(idx).text += tep_mesg;
  668. }
  669. // } else {
  670. // // chatHistory.value.at(idx).text += tep_mesg;
  671. // aiImgData.value.result += tep_mesg;
  672. // }
  673. // autoScrollSwitch.value && scrollToBottom(true);
  674. }
  675. })
  676. // console.log("handleAI", res)
  677. // aiImgData.value.result = res
  678. // aiImgData.value.loading = false
  679. } catch (error) {
  680. console.log("handleAI", error)
  681. aiImgData.value.loading = false;
  682. }
  683. };
  684. const initSignatureAndWitInfo = () => {
  685. (data.recorderInfo.length === 0 || !data.recorderInfo) &&
  686. (data.recorderInfo = [...recorderInfoType, recorderInfoType[4]]);
  687. (data.signatureInfo.length === 0 || !data.signatureInfo) &&
  688. Array.from(new Array(signatureInfoNum)).forEach(() => {
  689. data.signatureInfo.push({
  690. unit: "",
  691. job: "",
  692. });
  693. });
  694. (data.witnessInfo.length === 0 || !data.witnessInfo) &&
  695. Array.from(new Array(witnessInfoNum)).forEach(() => {
  696. data.witnessInfo.push({
  697. sex: 0,
  698. birthday: "",
  699. address: "",
  700. });
  701. });
  702. };
  703. onMounted(() => {
  704. listModels().then(res => {
  705. console.log("listModels", res)
  706. })
  707. initInfo();
  708. });
  709. const addRecorderInfo = () => {
  710. recorderInfoDialogShow.value = false;
  711. if (recorderInfoDialogSelect.value || recorderInfoDialogSelect.value === 0) {
  712. const newCrew = recorderInfoType.find(
  713. (i) => i.type === recorderInfoDialogSelect.value
  714. );
  715. data.recorderInfo.push({
  716. ...newCrew,
  717. job: "",
  718. name: "",
  719. unit: "",
  720. });
  721. // debugger;
  722. }
  723. };
  724. const removeRecorderInfo = async (index) => {
  725. if (await confirm("确定要删除此数据?")) {
  726. data.recorderInfo.splice(index, 1);
  727. }
  728. };
  729. const addSignatureInfo = async () => {
  730. if (await confirm("确定要添加新的现场勘验人员?")) {
  731. data.signatureInfo.push({
  732. unit: "",
  733. job: "",
  734. });
  735. }
  736. };
  737. const removeSignatureInfo = async (index) => {
  738. if (await confirm("确定要删除此数据?")) {
  739. data.signatureInfo.splice(index, 1);
  740. }
  741. };
  742. const addWitnessInfo = async () => {
  743. if (await confirm("确定要添加新的现场勘验见证人?")) {
  744. data.witnessInfo.push({
  745. sex: 0,
  746. birthday: "",
  747. address: "",
  748. });
  749. }
  750. };
  751. const backPageHandler = () => {
  752. router.back();
  753. };
  754. const removeWitnessInfo = async (index) => {
  755. if (await confirm("确定要删除此数据?")) {
  756. data.witnessInfo.splice(index, 1);
  757. }
  758. };
  759. const handleSave = async () => {
  760. console.log("data", data);
  761. for (var k in data) {
  762. if (data && data.hasOwnProperty(k)) {
  763. // console.log("Key is " + k);
  764. if (Array.isArray(data[k])) {
  765. data[k] = data[k].sort((a, b) => a - b);
  766. }
  767. }
  768. }
  769. let inquestFileId = fileId.value == -1 ? "" : fileId.value;
  770. let params = { ...data, caseId: caseId.value, inquestFileId };
  771. const res = await saveCaseInquestInfo(params);
  772. initInfo(res.data.inquestFileId);
  773. console.log("saveCaseInquestInfo", res);
  774. if (fileId.value == -1) {
  775. router.replace({
  776. name: RouteName.records,
  777. params: { caseId: caseId.value, fileId: res.data?.inquestFileId },
  778. });
  779. return;
  780. }
  781. if (res.code === 0) {
  782. ElMessage.success("保存成功!");
  783. }
  784. };
  785. const handleExport = async () => {
  786. let inquestFileId = fileId.value == -1 ? "" : fileId.value;
  787. let params = { ...data, caseId: caseId.value, inquestFileId };
  788. await saveCaseInquestInfo(params);
  789. const res = await exportCaseInquestInfo(fileId.value);
  790. console.log("res", res);
  791. saveAs(res, `勘验笔录.docx`);
  792. };
  793. </script>
  794. <style lang="scss">
  795. .records {
  796. max-width: 1280px;
  797. margin: 0 auto;
  798. padding: 20px;
  799. position: relative;
  800. background: #fff;
  801. .header {
  802. display: flex;
  803. justify-content: flex-endTime;
  804. position: sticky;
  805. top: 10px;
  806. z-index: 1000;
  807. background-color: white;
  808. }
  809. .input {
  810. height: 32px;
  811. line-height: 32px;
  812. margin: 0 8px;
  813. }
  814. .textarea {
  815. margin-right: 8px;
  816. margin-bottom: 20px;
  817. span {
  818. padding: 10px 0;
  819. display: inline-block;
  820. }
  821. // margin: 0 8px;
  822. }
  823. .line {
  824. display: inline-flex;
  825. width: 100%;
  826. flex-direction: row;
  827. align-items: center;
  828. margin-bottom: 25px;
  829. line-height: 38px;
  830. span {
  831. white-space: nowrap;
  832. }
  833. }
  834. }
  835. .title {
  836. text-align: center;
  837. margin-bottom: 30px;
  838. }
  839. .sub-tit {
  840. display: inline-block;
  841. padding-bottom: 20px;
  842. }
  843. .info {
  844. display: block;
  845. .inner {
  846. display: flex;
  847. flex-direction: row;
  848. width: 100%;
  849. .input {
  850. flex: 1;
  851. }
  852. .sec {
  853. flex: 1;
  854. display: inline-flex;
  855. align-items: center;
  856. justify-content: center;
  857. }
  858. }
  859. }
  860. .witnessInfo {
  861. background: #f5f5f5;
  862. padding: 15px;
  863. margin-top: 20px;
  864. margin-right: 8px;
  865. }
  866. .gap {
  867. margin: 15px 0;
  868. }
  869. .btn-container {
  870. padding: 20px 0;
  871. .btn {
  872. color: #26559b;
  873. width: 100%;
  874. &:hover {
  875. background: #f5f5f5;
  876. border-color: #dcdfe6;
  877. }
  878. }
  879. }
  880. .info {
  881. .del-btn {
  882. display: none;
  883. }
  884. &:hover {
  885. .del-btn {
  886. display: block;
  887. }
  888. }
  889. }
  890. </style>