index.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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. style="display: block;"
  481. size="large"
  482. >
  483. <el-option
  484. v-for="item in aiImgData.list"
  485. :key="item.num"
  486. :label="item.title"
  487. :value="item.url"
  488. />
  489. </el-select>
  490. <div class="viewImg mt-4 text-center" style="height: 400px; line-height: 400px; border-radius: 0px 0px 0px 0px;
  491. border: 1px solid #D9D9D9;">
  492. <img class="w-full h-full object-cover" v-if="aiImgData.src" :src="aiImgData.src" alt="" />
  493. <span v-else>预览选中的平面图</span>
  494. </div>
  495. </div>
  496. <div class="flex-1 text-center content-start" style="border-radius: 0px 0px 0px 0px;
  497. border: 1px solid #D9D9D9;min-height: 450px">
  498. <span style="line-height: 450px" v-if="aiImgData.loading">识别中,请稍后...</span>
  499. <span style="line-height: 450px" v-else-if="!aiImgData.result">请点击【识别】获取结果</span>
  500. <div class="text-left" style="height: 450px;padding: 10px; overflow: auto;white-space: pre-wrap" v-else v-html="aiImgData.result"></div>
  501. </div>
  502. </div>
  503. <template #footer>
  504. <div class="dialog-footer text-center flex">
  505. <div style="width: 50%">
  506. <el-button type="primary" :disabled="!aiImgData.src || aiImgData.loading" @click="handleAI"> 识别 </el-button>
  507. </div>
  508. <div style="width: 50%">
  509. <el-button :disabled="!aiImgData.result" @click="handleCopy"> 复制 </el-button>
  510. </div>
  511. </div>
  512. </template>
  513. </el-dialog>
  514. </div>
  515. </template>
  516. <script setup>
  517. import { onMounted, ref, watch, h, computed } from "vue";
  518. import { reactive } from "vue";
  519. import { router, RouteName } from "@/router";
  520. import {
  521. getCaseInquestInfo,
  522. saveCaseInquestInfo,
  523. exportCaseInquestInfo,
  524. getCaseInquestInfoOld,
  525. getAiByImage,
  526. getFloorList,
  527. } from "@/store/case";
  528. import { ElMessage, ElMessageBox } from "element-plus";
  529. import saveAs from "@/util/file-serve";
  530. import { CirclePlus, CircleClose, MagicStick } from "@element-plus/icons-vue";
  531. import { recorderInfoType, ChangeReasonType } from "./formData.ts";
  532. import { confirm } from "@/helper/message";
  533. import { chat, abort, listModels } from "@/util/ollama";
  534. import { copyTextToClipboard } from "@/util/index";
  535. const props = defineProps({ caseId: Number, title: String });
  536. console.log("router.currentRoute", router.currentRoute.value?.params);
  537. const fileId = computed(() => router.currentRoute.value?.params?.fileId);
  538. const caseId = computed(() => router.currentRoute.value?.params?.caseId);
  539. const isDisableExport = ref(false);
  540. const aiImgShow = ref(false)
  541. const aiImgData = ref({
  542. src: '',
  543. result: ``,
  544. loading: false,
  545. list: [],
  546. })
  547. const data = reactive({
  548. title: "",
  549. inquestNum: "", //现场勘验号
  550. deptName: "", //单位名称
  551. sendDept: "", //发送单位
  552. issuanceCount: "", // 份数
  553. makeTime: "", //制作时间
  554. recorder: "", // 笔录人
  555. issuanceOpinion: "", //签发意见
  556. reportDept: "", //报告单位
  557. times: [], // startTime ,endTime
  558. address: "", // 勘验地址
  559. inquestTime: "", //勘验时间
  560. inquestResource:
  561. "x年x月x日x单位接到报警称;x年x月x日x地点发生一起什么案事件,需要勘验现场, 接通知后,技术员xx,xx前往现场考察", //勘验范围
  562. protector: {
  563. name: "",
  564. unit: "",
  565. job: "",
  566. }, // 现场保护人
  567. protectionSituation: "", // 现场保护情况
  568. situation: [], //现场情况
  569. changeReason: [],
  570. changeReasonOtherValue: "",
  571. protectionMeasures: [], //保护措施
  572. weatherInfo: {
  573. type: [],
  574. temperature: "",
  575. humidity: "",
  576. windDirection: "",
  577. }, //天气情况
  578. light: [], //光线
  579. painter: "",
  580. photographer: "",
  581. inquestCommander: {
  582. name: "",
  583. unit: "",
  584. job: "",
  585. }, //现场勘验指挥人
  586. inquestSituation: "案发现场以XXX小区为中心,东侧为XXX路,西侧是XXX街,北侧为XXX路,南侧是XXX路。", //现场勘验情况
  587. imageNum: 0, //现场勘验制图数量
  588. photographNum: 0, //照相数量
  589. photographyMinNum: 0, //摄影数量
  590. photographySecNum: 0, //摄影数量
  591. recorderInfo: JSON.parse(JSON.stringify(recorderInfoType)),
  592. signatureInfo: [], //现场勘验人员
  593. witnessInfo: [],
  594. remark: "",
  595. });
  596. const signatureInfoNum = 4;
  597. const witnessInfoNum = 2;
  598. const recorderInfoDialogShow = ref(false);
  599. const recorderInfoDialogSelect = ref();
  600. const initInfo = async (inquestFileId) => {
  601. const res = await getCaseInquestInfoOld(inquestFileId || fileId.value);
  602. console.log("initInfo", res);
  603. if (!res.data) {
  604. isDisableExport.value = true;
  605. } else {
  606. isDisableExport.value = false;
  607. }
  608. for (var k in data) {
  609. if (res.data && res.data.hasOwnProperty(k)) {
  610. // console.log("Key is " + k);
  611. if (res.data[k]) {
  612. data[k] = res.data[k];
  613. }
  614. }
  615. }
  616. setTimeout(() => {
  617. initSignatureAndWitInfo();
  618. }, 500);
  619. };
  620. const handleCopy = () => {
  621. copyTextToClipboard(aiImgData.value.result);
  622. ElMessage.success("复制成功!");
  623. }
  624. const handleShowAi = async () => {
  625. const list = await getFloorList(caseId.value)
  626. aiImgData.value.list = list.filter((i) => i.url);
  627. aiImgData.value.src = list[0]?.url;
  628. aiImgShow.value = true;
  629. }
  630. //判断是否deepseek
  631. let isThink = ref(false);
  632. let testRegex = /deepseek/;
  633. const handleAI = async () => {
  634. aiImgData.value.loading = true;
  635. aiImgData.value.result = '';
  636. const item = aiImgData.value.list.find(i => i.url == aiImgData.value.src)
  637. try {
  638. // const res = await getAiByImage({imageUrl: imageUrl})
  639. chat('', item.params + item.paramContent).then(async stream => {
  640. for await (const part of stream) {
  641. // chatHistory.value.at(idx).text += part.message.content;
  642. let tep_mesg = part.message.content;
  643. console.log("isThinktep", tep_mesg);
  644. //判断是否是deepseek模型
  645. // if (testRegex.test(agentInfo.value.model)) {
  646. if (tep_mesg == "\u003c/think\u003e") {
  647. // isThink.value = true;
  648. aiImgData.value.loading = false;
  649. }
  650. if (!aiImgData.value.loading) {
  651. //清除think
  652. if (
  653. tep_mesg == "\u003cthink\u003e" ||
  654. tep_mesg == "\u003c/think\u003e"
  655. ) {
  656. // chatHistory.value.at(idx).think += "";
  657. } else {
  658. console.log("isThinktep_mesg", tep_mesg);
  659. aiImgData.value.result += tep_mesg;
  660. // chatHistory.value.at(idx).think += tep_mesg;
  661. }
  662. //如果结尾标签则停止拼接
  663. if (tep_mesg == "\u003c/think\u003e") {
  664. // isThink.value = false;
  665. }
  666. } else {
  667. // aiImgData.value.result += tep_mesg;
  668. // chatHistory.value.at(idx).text += tep_mesg;
  669. }
  670. // } else {
  671. // // chatHistory.value.at(idx).text += tep_mesg;
  672. // aiImgData.value.result += tep_mesg;
  673. // }
  674. // autoScrollSwitch.value && scrollToBottom(true);
  675. }
  676. console.log("handleAI完成", aiImgData.value.result)
  677. })
  678. // console.log("handleAI", res)
  679. // aiImgData.value.result = res
  680. // aiImgData.value.loading = false
  681. } catch (error) {
  682. console.log("handleAI", error)
  683. aiImgData.value.loading = false;
  684. }
  685. };
  686. const initSignatureAndWitInfo = () => {
  687. (data.recorderInfo.length === 0 || !data.recorderInfo) &&
  688. (data.recorderInfo = [...recorderInfoType, recorderInfoType[4]]);
  689. (data.signatureInfo.length === 0 || !data.signatureInfo) &&
  690. Array.from(new Array(signatureInfoNum)).forEach(() => {
  691. data.signatureInfo.push({
  692. unit: "",
  693. job: "",
  694. });
  695. });
  696. (data.witnessInfo.length === 0 || !data.witnessInfo) &&
  697. Array.from(new Array(witnessInfoNum)).forEach(() => {
  698. data.witnessInfo.push({
  699. sex: 0,
  700. birthday: "",
  701. address: "",
  702. });
  703. });
  704. };
  705. onMounted(() => {
  706. listModels().then(res => {
  707. console.log("listModels", res)
  708. })
  709. initInfo();
  710. });
  711. const addRecorderInfo = () => {
  712. recorderInfoDialogShow.value = false;
  713. if (recorderInfoDialogSelect.value || recorderInfoDialogSelect.value === 0) {
  714. const newCrew = recorderInfoType.find(
  715. (i) => i.type === recorderInfoDialogSelect.value
  716. );
  717. data.recorderInfo.push({
  718. ...newCrew,
  719. job: "",
  720. name: "",
  721. unit: "",
  722. });
  723. // debugger;
  724. }
  725. };
  726. const removeRecorderInfo = async (index) => {
  727. if (await confirm("确定要删除此数据?")) {
  728. data.recorderInfo.splice(index, 1);
  729. }
  730. };
  731. const addSignatureInfo = async () => {
  732. if (await confirm("确定要添加新的现场勘验人员?")) {
  733. data.signatureInfo.push({
  734. unit: "",
  735. job: "",
  736. });
  737. }
  738. };
  739. const removeSignatureInfo = async (index) => {
  740. if (await confirm("确定要删除此数据?")) {
  741. data.signatureInfo.splice(index, 1);
  742. }
  743. };
  744. const addWitnessInfo = async () => {
  745. if (await confirm("确定要添加新的现场勘验见证人?")) {
  746. data.witnessInfo.push({
  747. sex: 0,
  748. birthday: "",
  749. address: "",
  750. });
  751. }
  752. };
  753. const backPageHandler = () => {
  754. router.back();
  755. };
  756. const removeWitnessInfo = async (index) => {
  757. if (await confirm("确定要删除此数据?")) {
  758. data.witnessInfo.splice(index, 1);
  759. }
  760. };
  761. const handleSave = async () => {
  762. console.log("data", data);
  763. for (var k in data) {
  764. if (data && data.hasOwnProperty(k)) {
  765. // console.log("Key is " + k);
  766. if (Array.isArray(data[k])) {
  767. data[k] = data[k].sort((a, b) => a - b);
  768. }
  769. }
  770. }
  771. let inquestFileId = fileId.value == -1 ? "" : fileId.value;
  772. let params = { ...data, caseId: caseId.value, inquestFileId };
  773. const res = await saveCaseInquestInfo(params);
  774. initInfo(res.data.inquestFileId);
  775. console.log("saveCaseInquestInfo", res);
  776. if (fileId.value == -1) {
  777. router.replace({
  778. name: RouteName.records,
  779. params: { caseId: caseId.value, fileId: res.data?.inquestFileId },
  780. });
  781. return;
  782. }
  783. if (res.code === 0) {
  784. ElMessage.success("保存成功!");
  785. }
  786. };
  787. const handleExport = async () => {
  788. let inquestFileId = fileId.value == -1 ? "" : fileId.value;
  789. let params = { ...data, caseId: caseId.value, inquestFileId };
  790. await saveCaseInquestInfo(params);
  791. const res = await exportCaseInquestInfo(fileId.value);
  792. console.log("res", res);
  793. saveAs(res, `勘验笔录.docx`);
  794. };
  795. </script>
  796. <style lang="scss">
  797. .el-popper{
  798. max-width: 100% !important;
  799. }
  800. .records {
  801. max-width: 1280px;
  802. margin: 0 auto;
  803. padding: 20px;
  804. position: relative;
  805. background: #fff;
  806. .header {
  807. display: flex;
  808. justify-content: flex-endTime;
  809. position: sticky;
  810. top: 10px;
  811. z-index: 1000;
  812. background-color: white;
  813. }
  814. .input {
  815. height: 32px;
  816. line-height: 32px;
  817. margin: 0 8px;
  818. }
  819. .textarea {
  820. margin-right: 8px;
  821. margin-bottom: 20px;
  822. span {
  823. padding: 10px 0;
  824. display: inline-block;
  825. }
  826. // margin: 0 8px;
  827. }
  828. .line {
  829. display: inline-flex;
  830. width: 100%;
  831. flex-direction: row;
  832. align-items: center;
  833. margin-bottom: 25px;
  834. line-height: 38px;
  835. span {
  836. white-space: nowrap;
  837. }
  838. }
  839. }
  840. .title {
  841. text-align: center;
  842. margin-bottom: 30px;
  843. }
  844. .sub-tit {
  845. display: inline-block;
  846. padding-bottom: 20px;
  847. }
  848. .info {
  849. display: block;
  850. .inner {
  851. display: flex;
  852. flex-direction: row;
  853. width: 100%;
  854. .input {
  855. flex: 1;
  856. }
  857. .sec {
  858. flex: 1;
  859. display: inline-flex;
  860. align-items: center;
  861. justify-content: center;
  862. }
  863. }
  864. }
  865. .witnessInfo {
  866. background: #f5f5f5;
  867. padding: 15px;
  868. margin-top: 20px;
  869. margin-right: 8px;
  870. }
  871. .gap {
  872. margin: 15px 0;
  873. }
  874. .btn-container {
  875. padding: 20px 0;
  876. .btn {
  877. color: #26559b;
  878. width: 100%;
  879. &:hover {
  880. background: #f5f5f5;
  881. border-color: #dcdfe6;
  882. }
  883. }
  884. }
  885. .info {
  886. .del-btn {
  887. display: none;
  888. }
  889. &:hover {
  890. .del-btn {
  891. display: block;
  892. }
  893. }
  894. }
  895. </style>