voyageDetail.vue 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746
  1. <template>
  2. <div class="line-container-p24">
  3. <i class="el-icon-arrow-left"></i>
  4. <div
  5. class="dib go-back ml8 pointer"
  6. @click="router.replace('/voyage/voyageList')"
  7. >
  8. 返回航次列表
  9. </div>
  10. </div>
  11. <div class="container-title df aic jcsb">
  12. <div class="df aic">
  13. <div class="mr30">航次信息</div>
  14. <el-tooltip
  15. v-if="blockchainInfo"
  16. class="box-item"
  17. effect="light"
  18. :content="blockchainInfo.hash"
  19. placement="top"
  20. >
  21. <div class="pointer" style="font-size: 14px; font-weight: normal">
  22. 汇很多科技区块链认证
  23. </div>
  24. </el-tooltip>
  25. </div>
  26. <el-button
  27. v-auth="'DOWNLOADSHIPTRACK'"
  28. style="width: 220px; margin-right: 20px"
  29. type="primary"
  30. @click="downloadExcel"
  31. :loading="isLoadingExcel"
  32. >
  33. 下载船舶跟踪表
  34. </el-button>
  35. </div>
  36. <div class="line-container-p24">
  37. <div v-auth="'VOYAGEINFO'">
  38. <div class="line">
  39. <div class="info-line">
  40. <div class="info-line-title">航次名称</div>
  41. <el-input
  42. class="info-line-text"
  43. v-model="voyage.voyageName"
  44. disabled
  45. ></el-input>
  46. </div>
  47. <div class="info-gap" v-if="shipAudits.length"></div>
  48. <div class="info-line">
  49. <div class="info-line-title">货主</div>
  50. <el-input
  51. class="info-line-text"
  52. v-model="voyage.cargoOwnerName"
  53. disabled
  54. ></el-input>
  55. </div>
  56. </div>
  57. <!-- <div class="line">
  58. <div class="info-line">
  59. <div class="info-line-title">船东</div>
  60. <el-input
  61. class="info-line-text"
  62. v-model="voyage.shipOwnerName"
  63. disabled
  64. ></el-input>
  65. </div>
  66. <div class="info-line">
  67. <div class="info-line-title">船东手机号</div>
  68. <el-input
  69. class="info-line-text"
  70. v-model="voyage.shipOwnerPhone"
  71. disabled
  72. ></el-input>
  73. </div>
  74. </div> -->
  75. <div class="line">
  76. <div class="info-line">
  77. <div class="info-line-title">船舶名称</div>
  78. <el-input
  79. class="info-line-text"
  80. v-model="voyage.shipName"
  81. disabled
  82. ></el-input>
  83. </div>
  84. <div
  85. class="info-gap"
  86. v-if="shipAudits.length"
  87. @click="isCertsVisable = true"
  88. >
  89. 汇很多认证
  90. </div>
  91. <el-dialog
  92. @open="showCerts"
  93. v-model="isCertsVisable"
  94. destroy-on-close
  95. width="30%"
  96. >
  97. <Certs ref="certs"></Certs>
  98. </el-dialog>
  99. <div class="info-line">
  100. <div class="info-line-title">MMSI</div>
  101. <el-input
  102. class="info-line-text"
  103. v-model="voyage.shipMmsi"
  104. disabled
  105. ></el-input>
  106. </div>
  107. </div>
  108. <div id="map-container" class="map-container"></div>
  109. <div class="line" style="margin-top: 30px">
  110. <div class="info-line">
  111. <div class="info-line-title">开始时间</div>
  112. <el-input
  113. class="info-line-text"
  114. v-model="voyage.startTime"
  115. disabled
  116. ></el-input>
  117. </div>
  118. <div class="info-line">
  119. <div class="info-line-title">结束时间</div>
  120. <el-input
  121. class="info-line-text"
  122. v-model="voyage.endTime"
  123. disabled
  124. ></el-input>
  125. </div>
  126. </div>
  127. <div class="line">
  128. <div class="info-line">
  129. <div class="info-line-title">装货港</div>
  130. <el-input
  131. class="info-line-text"
  132. v-model="voyage.loadPort"
  133. disabled
  134. ></el-input>
  135. </div>
  136. <div class="info-line">
  137. <div class="info-line-title">卸货港</div>
  138. <el-input
  139. class="info-line-text"
  140. v-model="voyage.dischargePorts"
  141. disabled
  142. ></el-input>
  143. </div>
  144. </div>
  145. <div class="line">
  146. <div class="info-line">
  147. <div class="info-line-title">货种</div>
  148. <el-input
  149. class="info-line-text"
  150. v-model="voyage.cargo"
  151. disabled
  152. ></el-input>
  153. </div>
  154. <div class="info-line">
  155. <div style="width: 120px !important" class="info-line-title">
  156. 货量
  157. </div>
  158. <el-input
  159. style="width: 100px !important"
  160. class="info-line-text"
  161. v-model="voyage.tons"
  162. disabled
  163. ></el-input>
  164. <span class="unit">吨</span>
  165. <el-input
  166. style="width: 80px !important"
  167. class="info-line-text"
  168. v-model="voyage.pieces"
  169. disabled
  170. ></el-input>
  171. <span class="unit">件</span>
  172. </div>
  173. </div>
  174. </div>
  175. <div v-auth="'SHIPTRANS'">
  176. <div class="container-second-title df aic jcsb mt40">
  177. <div>船舶运输记录详情</div>
  178. <div style="margin-right: 20px">
  179. 信息更新时间 :
  180. <span style="font-size: 18px">
  181. {{ subStr(voyage.infoUpdateTime) }}</span
  182. >
  183. </div>
  184. </div>
  185. <div class="line-container-p24">
  186. <div class="line">
  187. <div class="info-line">
  188. <div class="info-line-title">到达装货港时间</div>
  189. <el-date-picker
  190. class="info-line-text"
  191. v-model="voyage.arrivalLoadPortTime"
  192. type="datetime"
  193. format="YYYY/MM/DD HH:mm:ss"
  194. value-format="YYYY/MM/DD HH:mm:ss"
  195. placeholder="到达装货港时间"
  196. :disabled="disabledStatus"
  197. ></el-date-picker>
  198. </div>
  199. <div class="info-line">
  200. <div class="info-line-title">实装货量</div>
  201. <el-input
  202. style="width: 100px !important"
  203. class="info-line-text"
  204. v-model="voyage.actualLoadTons"
  205. :disabled="disabledStatus"
  206. placeholder="实装吨位"
  207. ></el-input>
  208. <span class="unit">吨</span>
  209. <el-input
  210. style="width: 80px !important"
  211. class="info-line-text"
  212. v-model="voyage.actualLoadPieces"
  213. :disabled="disabledStatus"
  214. placeholder="实装件数"
  215. ></el-input>
  216. <span class="unit">件</span>
  217. </div>
  218. </div>
  219. <div class="line">
  220. <div class="info-line">
  221. <div class="info-line-title">装货开始时间</div>
  222. <el-date-picker
  223. class="info-line-text"
  224. v-model="voyage.loadStartTime"
  225. type="datetime"
  226. format="YYYY/MM/DD HH:mm:ss"
  227. value-format="YYYY/MM/DD HH:mm:ss"
  228. placeholder="装货开始时间"
  229. :disabled="disabledStatus"
  230. ></el-date-picker>
  231. </div>
  232. <div class="info-line">
  233. <div class="info-line-title">装货结束时间</div>
  234. <el-date-picker
  235. class="info-line-text"
  236. v-model="voyage.loadEndTime"
  237. type="datetime"
  238. format="YYYY/MM/DD HH:mm:ss"
  239. value-format="YYYY/MM/DD HH:mm:ss"
  240. placeholder="装货开始时间"
  241. :disabled="disabledStatus"
  242. ></el-date-picker>
  243. </div>
  244. </div>
  245. <el-tabs v-model="currentPortId" type="border-card" class="demo-tabs">
  246. <el-tab-pane
  247. v-for="(item, index) in voyage.voyageDetails"
  248. :label="item.portName + ' # ' + (index + 1)"
  249. :name="item.portId + ''"
  250. >
  251. <div class="line">
  252. <div class="info-line">
  253. <div class="info-line-title">开航时间</div>
  254. <el-date-picker
  255. class="info-line-text"
  256. v-model="item.setSailTime"
  257. type="datetime"
  258. @change="calExpectedArrivalTime"
  259. format="YYYY/MM/DD HH:mm:ss"
  260. value-format="YYYY/MM/DD HH:mm:ss"
  261. placeholder="开航时间"
  262. :disabled="disabledStatus"
  263. ></el-date-picker>
  264. </div>
  265. <div class="info-line">
  266. <div class="info-line-title">预计到港时间</div>
  267. <el-date-picker
  268. class="info-line-text"
  269. v-model="item.expectedArrivalTime"
  270. type="datetime"
  271. format="YYYY/MM/DD"
  272. value-format="YYYY/MM/DD HH:mm:ss"
  273. placeholder="预计到港时间"
  274. :disabled="disabledStatus"
  275. ></el-date-picker>
  276. </div>
  277. </div>
  278. <div class="line">
  279. <div class="info-line">
  280. <div class="info-line-title">实际到港时间</div>
  281. <el-date-picker
  282. class="info-line-text"
  283. v-model="item.actualArrivalTime"
  284. type="datetime"
  285. format="YYYY/MM/DD HH:mm:ss"
  286. value-format="YYYY/MM/DD HH:mm:ss"
  287. placeholder="实际到港时间"
  288. :disabled="disabledStatus"
  289. ></el-date-picker>
  290. </div>
  291. <!-- <div class="info-line">
  292. <div class="info-line-title">抵达目的地港时间</div>
  293. <el-date-picker
  294. class="info-line-text"
  295. v-model="voyage.arrivalPortTime"
  296. type="datetime"
  297. format="YYYY/MM/DD HH:mm:ss"
  298. value-format="YYYY/MM/DD HH:mm:ss"
  299. placeholder="抵达目的地港时间"
  300. :disabled="disabledStatus"
  301. ></el-date-picker>
  302. </div> -->
  303. </div>
  304. <div class="line">
  305. <div class="info-line">
  306. <div class="info-line-title">卸货开始时间</div>
  307. <el-date-picker
  308. class="info-line-text"
  309. v-model="item.dischargeStartTime"
  310. type="datetime"
  311. format="YYYY/MM/DD HH:mm:ss"
  312. value-format="YYYY/MM/DD HH:mm:ss"
  313. placeholder="卸货开始时间"
  314. :disabled="disabledStatus"
  315. ></el-date-picker>
  316. </div>
  317. <div class="info-line">
  318. <div class="info-line-title">卸货结束时间</div>
  319. <el-date-picker
  320. class="info-line-text"
  321. v-model="item.dischargeEndTime"
  322. type="datetime"
  323. format="YYYY/MM/DD HH:mm:ss"
  324. value-format="YYYY/MM/DD HH:mm:ss"
  325. placeholder="卸货结束时间"
  326. :disabled="disabledStatus"
  327. ></el-date-picker>
  328. </div>
  329. </div>
  330. <div class="line">
  331. <div class="info-line">
  332. <div class="info-line-title">实际卸货量</div>
  333. <el-input
  334. style="width: 100px !important"
  335. class="info-line-text"
  336. placeholder="实际卸货吨位"
  337. v-model="item.actualDischargeTons"
  338. :disabled="disabledStatus"
  339. ></el-input>
  340. <span class="unit">吨</span>
  341. <el-input
  342. style="width: 80px !important"
  343. class="info-line-text"
  344. placeholder="实际卸货件数"
  345. v-model="item.actualDischargePieces"
  346. :disabled="disabledStatus"
  347. ></el-input>
  348. <span class="unit">件</span>
  349. </div>
  350. <!-- <div class="info-line">
  351. <div class="info-line-title">是否购买保险</div>
  352. <el-checkbox
  353. v-model="voyage.hasInsurance"
  354. :checked="voyage.hasInsurance == 1"
  355. :disabled="disabledStatus"
  356. label="购买保险"
  357. ></el-checkbox>
  358. </div> -->
  359. </div>
  360. </el-tab-pane>
  361. </el-tabs>
  362. <div class="line">
  363. <div class="info-line">
  364. <div class="info-line-title">备注</div>
  365. <el-input
  366. class="info-line-textarea"
  367. v-model="voyage.remark"
  368. autosize
  369. type="textarea"
  370. :disabled="disabledStatus"
  371. ></el-input>
  372. </div>
  373. </div>
  374. </div>
  375. </div>
  376. </div>
  377. <div class="container-title">卸货信息</div>
  378. <div class="line-container-p24">
  379. <el-tabs
  380. v-model="currentDiscPortId"
  381. type="card"
  382. class="demo-tabs"
  383. @tab-click="changeDiscPortTab"
  384. >
  385. <el-tab-pane
  386. v-for="(item, index) in voyage.voyageDetails"
  387. :label="item.portName + ' # ' + (index + 1)"
  388. :name="item.portId + ''"
  389. ></el-tab-pane>
  390. </el-tabs>
  391. <div>
  392. <div class="container-second-title df aic jcsb">
  393. <div>天气信息</div>
  394. </div>
  395. <el-table style="width: 1200px" :data="weatherTableData" stripe>
  396. <el-table-column
  397. type="index"
  398. label="序号"
  399. min-width="120"
  400. align="center"
  401. ></el-table-column>
  402. <el-table-column
  403. prop="weather"
  404. label="天气"
  405. min-width="120"
  406. align="center"
  407. ></el-table-column>
  408. <el-table-column
  409. prop="temperature"
  410. label="温度"
  411. min-width="100"
  412. align="center"
  413. ></el-table-column>
  414. <el-table-column
  415. prop="winddirection"
  416. label="风向"
  417. min-width="100"
  418. align="center"
  419. ></el-table-column>
  420. <el-table-column
  421. prop="windpower"
  422. label="风力"
  423. min-width="100"
  424. align="center"
  425. ></el-table-column>
  426. <el-table-column
  427. prop="reporttime"
  428. label="记录时间"
  429. min-width="100"
  430. align="center"
  431. ></el-table-column>
  432. </el-table>
  433. <div style="width: 1200px; text-align: right; margin-top: 43px">
  434. <el-pagination
  435. background
  436. layout="prev, pager, next"
  437. :total="weatherTotal"
  438. @current-change="weatherPageChange"
  439. ></el-pagination>
  440. </div>
  441. <div class="hr m30-0"></div>
  442. </div>
  443. <div v-auth="'LABDETAIL'">
  444. <div class="container-second-title df aic jcsb">
  445. <div>提单信息</div>
  446. </div>
  447. <el-table :data="labTableData" stripe style="width: 1200px">
  448. <el-table-column
  449. type="index"
  450. label="序号"
  451. min-width="120"
  452. align="center"
  453. ></el-table-column>
  454. <el-table-column
  455. prop="billingDate"
  456. label="开单日期"
  457. min-width="120"
  458. align="center"
  459. ></el-table-column>
  460. <el-table-column
  461. prop="billingNum"
  462. label="开单数量"
  463. min-width="100"
  464. align="center"
  465. ></el-table-column>
  466. <el-table-column label="单据" min-width="150" align="center">
  467. <template v-slot="scope">
  468. <el-button
  469. @click="showLab(scope.row, scope.$index, '查看提单')"
  470. type="primary"
  471. size="small"
  472. >
  473. 查看
  474. </el-button>
  475. </template>
  476. </el-table-column>
  477. </el-table>
  478. <div style="text-align: right; margin-top: 43px; width: 1200px">
  479. <el-pagination
  480. background
  481. layout="prev, pager, next"
  482. :total="labTotal"
  483. @current-change="labPageChange"
  484. ></el-pagination>
  485. </div>
  486. <el-dialog
  487. v-model="isAddLabVisable"
  488. :title="labModalType"
  489. width="780px"
  490. center
  491. @close="cancelUploadLab"
  492. >
  493. <el-form
  494. :model="labForm"
  495. inline
  496. style="margin-bottom: 20px"
  497. label-width="100px"
  498. >
  499. <el-form-item label="开单日期">
  500. <el-date-picker
  501. class="info-line-text"
  502. v-model="labForm.billingDate"
  503. type="date"
  504. format="YYYY/MM/DD"
  505. value-format="YYYY/MM/DD"
  506. placeholder="开单日期"
  507. disabled
  508. ></el-date-picker>
  509. </el-form-item>
  510. <el-form-item label="开单数量">
  511. <el-input
  512. style="width: 240px"
  513. v-model="labForm.billingNum"
  514. placeholder="开单数量"
  515. disabled
  516. ></el-input>
  517. </el-form-item>
  518. <el-form-item label="提单">
  519. <Uploader
  520. disabled
  521. :actionUrl="store.state.wayBillUrl"
  522. :uploaderId="'labLoad'"
  523. :params="labParams"
  524. @onSendFileList="getLabBillList"
  525. :fileList="labBillList"
  526. uploadText="上传提单"
  527. :limit="1"
  528. ></Uploader>
  529. </el-form-item>
  530. </el-form>
  531. </el-dialog>
  532. <div class="hr m30-0"></div>
  533. </div>
  534. <div v-auth="'SHIPDISCHARGE'">
  535. <div class="container-second-title df aic jcsb">
  536. <div>卸货记录</div>
  537. <el-button
  538. v-auth="'DOWNLOADDISCHARGE'"
  539. @click="exportDischargeExcel"
  540. style="width: 220px; margin-right: 20px"
  541. type="primary"
  542. :loading="isDischargeLoadingExcel"
  543. >下载卸货信息</el-button
  544. >
  545. </div>
  546. <el-table :data="dischargeList" stripe style="width: 1200px">
  547. <el-table-column
  548. type="index"
  549. label="序号"
  550. min-width="80"
  551. align="center"
  552. ></el-table-column>
  553. <el-table-column
  554. prop="dischargeTime"
  555. label="卸货时间"
  556. min-width="120"
  557. align="center"
  558. ></el-table-column>
  559. <el-table-column
  560. prop="dischargeTons"
  561. label="卸货吨位"
  562. min-width="100"
  563. align="center"
  564. ></el-table-column>
  565. <el-table-column
  566. prop="dischargePieces"
  567. label="卸货件数"
  568. min-width="100"
  569. align="center"
  570. ></el-table-column>
  571. <el-table-column label="磅单" min-width="150" align="center">
  572. <template v-slot="scope">
  573. <el-button
  574. @click="showUpdateDischarge(scope.row, scope.$index)"
  575. type="primary"
  576. size="small"
  577. v-if="scope.row.files"
  578. >
  579. 查看
  580. </el-button>
  581. </template>
  582. </el-table-column>
  583. </el-table>
  584. <div style="width: 1200px; text-align: right; margin-top: 43px">
  585. <el-pagination
  586. background
  587. layout="prev, pager, next"
  588. :total="total"
  589. @current-change="pageChange"
  590. ></el-pagination>
  591. </div>
  592. <div class="hr m30-0"></div>
  593. </div>
  594. <el-dialog v-model="dialogVisible" title="图片预览" width="30%">
  595. <el-image
  596. :src="dialogImageUrl"
  597. style="height: 100%; width: 100%"
  598. ></el-image>
  599. </el-dialog>
  600. <div v-auth="'CARLOAD'">
  601. <div class="container-second-title df aic jcsb mt40">
  602. <div>汽车装货记录详情</div>
  603. </div>
  604. <el-table :data="truckTableData" stripe>
  605. <el-table-column
  606. type="index"
  607. label="序号"
  608. min-width="120"
  609. align="center"
  610. ></el-table-column>
  611. <el-table-column
  612. prop="portName"
  613. label="港口名称"
  614. min-width="100"
  615. align="center"
  616. ></el-table-column>
  617. <el-table-column
  618. prop="weighTime"
  619. label="称重时间"
  620. min-width="120"
  621. align="center"
  622. ></el-table-column>
  623. <el-table-column
  624. prop="carNum"
  625. label="车号"
  626. min-width="100"
  627. align="center"
  628. ></el-table-column>
  629. <el-table-column
  630. prop="cargoName"
  631. label="货物名称"
  632. min-width="120"
  633. align="center"
  634. ></el-table-column>
  635. <el-table-column
  636. prop="shippingUnit"
  637. label="发货单位"
  638. min-width="100"
  639. align="center"
  640. ></el-table-column>
  641. <el-table-column
  642. prop="receivingUnit"
  643. label="收货单位"
  644. min-width="120"
  645. align="center"
  646. ></el-table-column>
  647. <el-table-column
  648. prop="grossWeight"
  649. label="毛重"
  650. min-width="100"
  651. align="center"
  652. ></el-table-column>
  653. <el-table-column
  654. prop="tare"
  655. label="皮重"
  656. min-width="120"
  657. align="center"
  658. ></el-table-column>
  659. <el-table-column
  660. prop="netWeight"
  661. label="净重"
  662. min-width="100"
  663. align="center"
  664. ></el-table-column>
  665. <el-table-column
  666. prop="shipName"
  667. label="货船名称"
  668. min-width="120"
  669. align="center"
  670. ></el-table-column>
  671. <el-table-column
  672. prop="weigher"
  673. label="司磅员"
  674. min-width="100"
  675. align="center"
  676. ></el-table-column>
  677. <el-table-column label="单据" min-width="150" align="center">
  678. <template v-slot="scope">
  679. <el-button
  680. @click="showTruckRecord(scope.row, scope.$index, '查看单据')"
  681. type="primary"
  682. size="small"
  683. >
  684. 查看
  685. </el-button>
  686. </template>
  687. </el-table-column>
  688. </el-table>
  689. <div style="text-align: right; margin-top: 43px">
  690. <el-pagination
  691. background
  692. layout="prev, pager, next"
  693. :total="truckTotal"
  694. @current-change="truckPageChange"
  695. ></el-pagination>
  696. </div>
  697. </div>
  698. <el-dialog
  699. v-model="isAddTruckRecordVisable"
  700. title="查看记录"
  701. width="780px"
  702. center
  703. >
  704. <el-form
  705. :model="truckRecordForm"
  706. inline
  707. style="margin-bottom: 20px"
  708. label-width="100px"
  709. >
  710. <el-form-item label="港口名称">
  711. <el-input
  712. style="width: 240px"
  713. v-model="truckRecordForm.portName"
  714. placeholder="港口名称"
  715. ></el-input>
  716. </el-form-item>
  717. <el-form-item label="称重时间">
  718. <el-date-picker
  719. class="info-line-text"
  720. v-model="truckRecordForm.weighTime"
  721. type="datetime"
  722. format="YYYY/MM/DD HH:mm:ss"
  723. value-format="YYYY/MM/DD HH:mm:ss"
  724. placeholder="称重时间"
  725. ></el-date-picker>
  726. </el-form-item>
  727. <el-form-item label="车号">
  728. <el-input
  729. style="width: 240px"
  730. v-model="truckRecordForm.carNum"
  731. placeholder="车号"
  732. ></el-input>
  733. </el-form-item>
  734. <el-form-item label="货物名称">
  735. <el-input
  736. style="width: 240px"
  737. v-model="truckRecordForm.cargoName"
  738. placeholder="货物名称"
  739. ></el-input>
  740. </el-form-item>
  741. <el-form-item label="发货单位">
  742. <el-input
  743. style="width: 240px"
  744. v-model="truckRecordForm.shippingUnit"
  745. placeholder="发货单位"
  746. ></el-input>
  747. </el-form-item>
  748. <el-form-item label="毛重">
  749. <el-input
  750. style="width: 240px"
  751. v-model="truckRecordForm.grossWeight"
  752. placeholder="毛重"
  753. ></el-input>
  754. </el-form-item>
  755. <el-form-item label="收货单位">
  756. <el-input
  757. style="width: 240px"
  758. v-model="truckRecordForm.receivingUnit"
  759. placeholder="收货单位"
  760. ></el-input>
  761. </el-form-item>
  762. <el-form-item label="皮重">
  763. <el-input
  764. style="width: 240px"
  765. v-model="truckRecordForm.tare"
  766. placeholder="皮重"
  767. ></el-input>
  768. </el-form-item>
  769. <el-form-item label="运输单位">
  770. <el-input
  771. style="width: 240px"
  772. v-model="truckRecordForm.transUnit"
  773. placeholder="运输单位"
  774. ></el-input>
  775. </el-form-item>
  776. <el-form-item label="净重">
  777. <el-input
  778. style="width: 240px"
  779. v-model="truckRecordForm.netWeight"
  780. placeholder="净重"
  781. ></el-input>
  782. </el-form-item>
  783. <el-form-item label="货船名称">
  784. <el-input
  785. style="width: 240px"
  786. v-model="truckRecordForm.shipName"
  787. placeholder="货船名称"
  788. ></el-input>
  789. </el-form-item>
  790. <el-form-item label="司磅员">
  791. <el-input
  792. style="width: 240px"
  793. v-model="truckRecordForm.weigher"
  794. placeholder="司磅员"
  795. ></el-input>
  796. </el-form-item>
  797. <el-form-item label="汽车装货单">
  798. <Uploader
  799. actionUrl="#"
  800. :uploaderId="'truckLoad'"
  801. :params="truckLoadParams"
  802. @onSendFileList="getTruckLoadBillList"
  803. :fileList="truckRecordBillList"
  804. uploadText="上传装货单"
  805. :limit="1"
  806. disabled
  807. ></Uploader>
  808. </el-form-item>
  809. </el-form>
  810. </el-dialog>
  811. </div>
  812. <div v-auth="'BILLINFO'">
  813. <div class="container-title df aic jcsb">
  814. 单据信息
  815. <el-button
  816. style="margin-right: 30px"
  817. size="medium"
  818. type="primary"
  819. v-auth="'BILLDOWNLOAD'"
  820. @click="downloadBillZip"
  821. :loading="billZipLoading"
  822. >下载单据</el-button
  823. >
  824. </div>
  825. <div class="line-container-p24" style="padding-left: 60px">
  826. <div class="df aic">
  827. <div class="info-line-title">保险单:</div>
  828. <el-image
  829. style="width: 200px; height: 200px; margin-right: 20px"
  830. :src="item.viewUrl"
  831. v-for="item in policyList"
  832. :key="item"
  833. @click="openMediaModal(item.viewUrl, 1, '保险单查看')"
  834. ></el-image>
  835. </div>
  836. <hr class="hr m30-0" />
  837. <div class="df aic">
  838. <div class="info-line-title">运单:</div>
  839. <el-image
  840. style="width: 200px; height: 200px; margin-right: 20px"
  841. :src="item.viewUrl"
  842. v-for="item in voyageBill"
  843. :key="item"
  844. @click="openMediaModal(item.viewUrl, 1, '运单查看')"
  845. ></el-image>
  846. </div>
  847. </div>
  848. </div>
  849. <div v-auth="'VOYAGEIMAGE'">
  850. <div class="container-title">航次图片</div>
  851. <div class="line-container-p24">
  852. <div v-if="medias.length" class="medias-content df ffw">
  853. <div class="pic-container">
  854. <div v-for="(item, index) in medias" :key="item" class="pic-main">
  855. <div
  856. :class="[
  857. 'box',
  858. index % 2 == 0 ? '' : 'bottom-box',
  859. item.status == 1 ? 'now-box' : '',
  860. ]"
  861. >
  862. <div class="card-note">
  863. {{ item.shipName }} 拍摄于
  864. <br />
  865. {{ item.createTime }}
  866. <br />
  867. 天气 : {{ item.weather.weather }} - 气温 :
  868. {{ item.weather.temperature }}℃
  869. </div>
  870. <div class="medias-box mb10" style="position: relative">
  871. <el-image
  872. v-if="item.mediaType == 1"
  873. style="width: 100%; height: 100%"
  874. fit="contain"
  875. :src="item.downloadUrl"
  876. @click="openMediaModal(item.downloadUrl, 1, '图片审核')"
  877. ></el-image>
  878. <video
  879. style="width: 100%; height: 100%"
  880. v-else
  881. :src="item.downloadUrl"
  882. ></video>
  883. <img
  884. @click="openMediaModal(item.downloadUrl, 2, '视频审核')"
  885. v-if="item.mediaType == 2"
  886. src="../../assets/icon-player.png"
  887. style="
  888. object-fit: contain;
  889. width: 40px;
  890. height: 40px;
  891. position: absolute;
  892. top: calc(50% - 20px);
  893. left: calc(50% - 20px);
  894. background: #fff;
  895. border-radius: 50%;
  896. "
  897. alt=""
  898. />
  899. </div>
  900. </div>
  901. <div
  902. :class="[
  903. 's-line',
  904. index % 2 == 0 ? '' : 'top210px',
  905. item.status == 1 ? 'now-s-line' : '',
  906. ]"
  907. ></div>
  908. <div :class="['point', item.status == 1 ? '' : 'now-point']"></div>
  909. <div
  910. :class="['l-line', item.status == 1 ? 'now-l-line' : '']"
  911. v-if="index + 1 != medias.length"
  912. ></div>
  913. </div>
  914. </div>
  915. </div>
  916. <el-dialog v-model="mediaModal" :title="modalTitle">
  917. <el-image
  918. v-if="modalType == 1"
  919. style="height: 60vh; display: flex"
  920. fit="contain"
  921. :src="currentUrl"
  922. :preview-src-list="modalPreview"
  923. ></el-image>
  924. <video
  925. v-else
  926. autoplay
  927. controls
  928. style="width: 100%; height: 100%"
  929. :src="currentUrl"
  930. ></video>
  931. </el-dialog>
  932. <el-dialog
  933. v-model="updateDischargeDialog"
  934. title="查看记录"
  935. width="700px"
  936. center
  937. >
  938. <el-form :model="updateForm" style="margin-bottom: 20px">
  939. <!-- <el-form-item label="记录ID">
  940. <span style="padding-left: 20px">{{ updateForm.id }}</span>
  941. </el-form-item> -->
  942. <el-form-item label="卸货时间">
  943. <el-date-picker
  944. class="info-line-text"
  945. v-model="updateForm.dischargeTime"
  946. type="datetime"
  947. format="YYYY/MM/DD HH:mm:ss"
  948. value-format="YYYY/MM/DD HH:mm:ss"
  949. placeholder="卸货时间"
  950. disabled
  951. ></el-date-picker>
  952. </el-form-item>
  953. <el-form-item label="卸货吨位">
  954. <el-input
  955. style="width: 240px"
  956. v-model="updateForm.dischargeTons"
  957. placeholder="卸货吨位"
  958. disabled
  959. ></el-input>
  960. </el-form-item>
  961. <el-form-item label="磅单查看">
  962. <el-image
  963. style="width: 200px; height: 200px; margin-right: 20px"
  964. v-for="item in updatePoundBillList"
  965. :src="item.viewUrl"
  966. :key="item"
  967. @click="openMediaModal(item.viewUrl, 1, '磅单查看')"
  968. ></el-image>
  969. </el-form-item>
  970. </el-form>
  971. </el-dialog>
  972. </div>
  973. </div>
  974. </template>
  975. <script setup>
  976. import { onMounted, reactive, ref, toRefs } from "vue";
  977. import api from "../../apis/fetch";
  978. import { useRoute } from "vue-router";
  979. import _ from "lodash";
  980. import router from "../../router";
  981. import store from "../../store";
  982. import { ElNotification, ElMessageBox, ElMessage } from "element-plus";
  983. import downloadBlobFile from "../../utils/downloadBlobFile";
  984. import url from "../../apis/config";
  985. const route = useRoute();
  986. let map = ref();
  987. let voyage = ref({});
  988. let medias = ref([]);
  989. let coordinates = ref();
  990. let previewSrcList = ref([]);
  991. let policyList = ref([]);
  992. let previewPoundList = ref([]);
  993. let shipAudits = ref([]);
  994. let certs = ref(null);
  995. let isCertsVisable = ref(false);
  996. function showCerts() {
  997. setTimeout(() => {
  998. certs.value.initCerts(shipAudits.value);
  999. });
  1000. }
  1001. async function getVoyageDetail(isInit) {
  1002. policyList.value = [];
  1003. voyageBill.value = [];
  1004. previewSrcList.value = [];
  1005. let res = await api.getVoyageDetail({
  1006. type: localStorage.userType,
  1007. voyageId: route.query.id,
  1008. });
  1009. if (res.data.status == 0) {
  1010. ElNotification({
  1011. type: "success",
  1012. title: res.data.msg,
  1013. });
  1014. blockchainInfo.value = res.data.result.blockChain;
  1015. coordinates.value = res.data.result.coordinates;
  1016. voyage.value = res.data.result.voyage;
  1017. currentPortId.value = voyage.value.voyageDetails[0].portId + "";
  1018. currentDiscPortId.value = voyage.value.voyageDetails[0].portId + "";
  1019. medias.value = res.data.result.medias;
  1020. shipAudits.value = res.data.result.shipAudits;
  1021. for (let i of res.data.result.policys || []) {
  1022. policyList.value.push({
  1023. ...i,
  1024. url: i.viewUrl,
  1025. });
  1026. }
  1027. for (let i of res.data.result.waybills) {
  1028. voyageBill.value.push({
  1029. ...i,
  1030. url: i.viewUrl,
  1031. });
  1032. }
  1033. for (let i of medias.value) {
  1034. previewSrcList.value.push(i.downloadUrl);
  1035. }
  1036. if (isInit) {
  1037. getDischargeList();
  1038. getTruckLoadRecord();
  1039. getLabList();
  1040. getPortWeatherList();
  1041. initMap();
  1042. }
  1043. } else {
  1044. console.log(res);
  1045. ElNotification({
  1046. type: "error",
  1047. title: res.data.msg,
  1048. });
  1049. }
  1050. }
  1051. let total = ref(0);
  1052. function pageChange(e) {
  1053. dischargeCurrentPage.value = e;
  1054. getDischargeList();
  1055. }
  1056. async function addDischarge() {
  1057. if (!formInline.value.dischargeTime || !formInline.value.dischargeTons)
  1058. return;
  1059. let res = await api.addDischarge({
  1060. ...formInline.value,
  1061. voyageId: route.query.id,
  1062. });
  1063. if (res.data.status == 0) {
  1064. getDischargeList(1);
  1065. formInline.value = {};
  1066. } else {
  1067. console.log(res);
  1068. }
  1069. }
  1070. async function deleteDischarge(id, index) {
  1071. let res = await api.deleteDischarge({
  1072. id,
  1073. });
  1074. if (res.data.status == 0) {
  1075. dischargeList.value.splice(index, 1);
  1076. ElNotification({
  1077. type: "success",
  1078. title: res.data.msg,
  1079. });
  1080. } else {
  1081. console.log(res);
  1082. ElNotification({
  1083. type: "error",
  1084. title: res.data.msg,
  1085. });
  1086. }
  1087. }
  1088. async function exportExcel() {}
  1089. let dischargeCurrentPage = ref(1);
  1090. let dischargeList = ref();
  1091. let formInline = ref({});
  1092. async function getDischargeList(type) {
  1093. let res = await api.getDischargeList({
  1094. voyageId: route.query.id,
  1095. portId: currentDiscPortId.value,
  1096. currentPage: dischargeCurrentPage.value,
  1097. size: 10,
  1098. });
  1099. if (res.data.status == 0) {
  1100. dischargeList.value = res.data.result;
  1101. total.value = res.data.total;
  1102. } else {
  1103. console.log(res);
  1104. }
  1105. }
  1106. let updateForm = ref({});
  1107. let updateDischargeDialog = ref(false);
  1108. let currentUpdateIndex = ref(-1);
  1109. async function updateDischarge() {
  1110. let res = await api.updateDischarge({
  1111. ...updateForm.value,
  1112. });
  1113. if (res.data.status == 0) {
  1114. dischargeList.value[currentUpdateIndex.value] = res.data.result;
  1115. cancelUpdateDischarge();
  1116. ElNotification({
  1117. type: "success",
  1118. title: res.data.msg,
  1119. });
  1120. } else {
  1121. console.log(res);
  1122. ElNotification({
  1123. type: "error",
  1124. title: res.data.msg,
  1125. });
  1126. }
  1127. }
  1128. let updatePoundParams = ref([]);
  1129. let updatePoundBillList = ref([]);
  1130. function showUpdateDischarge(item, index) {
  1131. updateDischargeDialog.value = true;
  1132. updatePoundBillList.value = [];
  1133. let { id, dischargeTons, dischargeTime, voyageId, files } = item;
  1134. updatePoundBillList.value = files;
  1135. updateForm.value = {
  1136. id,
  1137. dischargeTons,
  1138. dischargeTime,
  1139. };
  1140. currentUpdateIndex.value = index;
  1141. }
  1142. function cancelUpdateDischarge() {
  1143. updateDischargeDialog.value = false;
  1144. updateForm.value = {};
  1145. currentUpdateIndex.value = -1;
  1146. }
  1147. function initMap() {
  1148. map.value = new AMap.Map("map-container", {
  1149. zoom: 11, //级别
  1150. center: [120.563757, 31.891174], //中心点坐标
  1151. mapStyle: "amap://styles/f48d96805f5fa7f5aada657c5ee37017",
  1152. zoomEnable: false,
  1153. dragEnable: false,
  1154. });
  1155. let toolBar = new AMap.ToolBar({
  1156. position: {
  1157. top: "40px",
  1158. right: "40px",
  1159. },
  1160. });
  1161. let hawkEye = new AMap.HawkEye({
  1162. opened: false,
  1163. });
  1164. // map.value.addControl(toolBar);
  1165. map.value.addControl(hawkEye);
  1166. let markers = [];
  1167. for (let i of medias.value) {
  1168. let content = `<div style='width:160px'>
  1169. ${
  1170. i.audit == 1
  1171. ? `<img id='img${i.id}' style='width:160px;height:160px;object-fit:contain;' src='${i.viewUrl}'/>`
  1172. : ``
  1173. }
  1174. <img src='https://hhd-pat-1255802371.cos.ap-shanghai.myqcloud.com/frontend/ship-red-icon.png' style='display:block;width:20px;height:20px;margin:6px auto'/
  1175. </div>`;
  1176. let marker = new AMap.Marker({
  1177. content,
  1178. position: new AMap.LngLat(i.longitude, i.latitude),
  1179. offset: new AMap.Pixel(-75, i.audit == 1 ? -195 : -30),
  1180. });
  1181. if (i.audit == 1) {
  1182. marker.on("click", () => {
  1183. openMediaModal(i.viewUrl, 1, "航次图片", i);
  1184. });
  1185. }
  1186. markers.push(marker);
  1187. }
  1188. let overlayGroups = new AMap.OverlayGroup(markers);
  1189. map.value.on("complete", function () {
  1190. let t = setTimeout(() => {
  1191. map.value.add(overlayGroups);
  1192. map.value.setFitView(markers, true, [200, 50, 0, 0], 18);
  1193. clearTimeout(t);
  1194. }, 2000);
  1195. });
  1196. }
  1197. function setShipMarker(longitude = 121.524761, latitude = 31.228721) {
  1198. map.value.setCenter([longitude, latitude]);
  1199. var marker = new AMap.Marker({
  1200. position: new AMap.LngLat(longitude, latitude),
  1201. offset: new AMap.Pixel(-20, -20),
  1202. size: new AMap.Size(80, 80),
  1203. icon: "https://hhd-pat-1255802371.cos.ap-shanghai.myqcloud.com/frontend/ship-red-icon.png", // 添加 Icon 图标 URL
  1204. title: "",
  1205. });
  1206. map.value.add(marker);
  1207. }
  1208. let disabledStatus = ref(true);
  1209. let updateCache = {};
  1210. function changeVoyageInfo() {
  1211. updateCache = _.cloneDeep(voyage.value);
  1212. disabledStatus.value = false;
  1213. }
  1214. function cancelVoyageChange() {
  1215. voyage.value = updateCache;
  1216. disabledStatus.value = true;
  1217. }
  1218. async function submitVoyageChange() {
  1219. let {
  1220. id,
  1221. transStatus,
  1222. loadStartTime,
  1223. loadEndTime,
  1224. dischargeStartTime,
  1225. dischargeEndTime,
  1226. actualDischargeTons,
  1227. remark,
  1228. } = voyage.value;
  1229. let res = await api.updateVoyage({
  1230. id,
  1231. transStatus,
  1232. loadStartTime,
  1233. loadEndTime,
  1234. dischargeStartTime,
  1235. dischargeEndTime,
  1236. actualDischargeTons,
  1237. remark,
  1238. });
  1239. if (res.data.status == 0) {
  1240. ElNotification({
  1241. type: "success",
  1242. title: res.data.msg,
  1243. });
  1244. disabledStatus.value = true;
  1245. } else {
  1246. ElNotification({
  1247. type: "error",
  1248. title: res.data.msg,
  1249. });
  1250. console.log(res);
  1251. }
  1252. }
  1253. let options = ref([
  1254. { value: 0, label: "请选择" },
  1255. {
  1256. value: 1,
  1257. label: "航行",
  1258. },
  1259. {
  1260. value: 2,
  1261. label: "停泊",
  1262. },
  1263. {
  1264. value: 3,
  1265. label: "装货",
  1266. },
  1267. {
  1268. value: 4,
  1269. label: "运输中",
  1270. },
  1271. {
  1272. value: 5,
  1273. label: "卸货",
  1274. },
  1275. ]);
  1276. async function finishVoyage() {
  1277. if (!voyage.value.dischargeEndTime) return;
  1278. let res = await api.finishVoyage({
  1279. voyageId: route.query.id,
  1280. });
  1281. if (res.data.status == 0) {
  1282. voyage.value.voyageStatus = 2;
  1283. ElNotification({
  1284. type: "success",
  1285. title: res.data.msg,
  1286. });
  1287. } else {
  1288. ElNotification({
  1289. type: "error",
  1290. title: res.data.msg,
  1291. });
  1292. console.log(res);
  1293. }
  1294. }
  1295. let currentUrl = ref("");
  1296. let mediaModal = ref(false);
  1297. let modalType = ref(1);
  1298. let modalTitle = ref();
  1299. let modalPreview = ref([]);
  1300. function openMediaModal(url, type, title) {
  1301. console.log(url, type, title);
  1302. modalPreview.value = [url];
  1303. modalTitle.value = title;
  1304. modalType.value = type;
  1305. currentUrl.value = url;
  1306. mediaModal.value = true;
  1307. }
  1308. async function auditMedia(mediaId, a, index, mediaType) {
  1309. console.log(mediaId, a, index, mediaType);
  1310. let res = await api.auditMedia({
  1311. mediaId,
  1312. audit: a,
  1313. });
  1314. if (res.data.status == 0) {
  1315. medias.value[index].audit = a;
  1316. ElNotification({
  1317. type: "success",
  1318. title: res.data.msg,
  1319. });
  1320. } else {
  1321. console.log(res);
  1322. }
  1323. }
  1324. let dialogImageUrl = ref();
  1325. let dialogVisible = ref(false);
  1326. function handlePictureCardPreview(file) {
  1327. dialogVisible.value = true;
  1328. dialogImageUrl.value = file.url;
  1329. }
  1330. async function handleRemoveBill(file, list) {
  1331. let cache = _.cloneDeep(voyageBill.value);
  1332. console.log(cache);
  1333. ElMessageBox.confirm("确认删除运单?", "Warning", {
  1334. confirmButtonText: "删除",
  1335. cancelButtonText: "取消",
  1336. type: "warning",
  1337. })
  1338. .then(async () => {
  1339. let { id } = file;
  1340. let res = await api.deleteWaybill({
  1341. id,
  1342. });
  1343. if (res.data.status == 0) {
  1344. ElMessage({
  1345. message: "删除成功!",
  1346. type: "success",
  1347. });
  1348. voyageBill.value = list;
  1349. }
  1350. })
  1351. .catch(() => {
  1352. voyageBill.value = cache;
  1353. ElMessage({
  1354. type: "info",
  1355. message: "取消删除",
  1356. });
  1357. });
  1358. }
  1359. let voyageBill = ref([]);
  1360. function billUploadSuccess(response, file, list) {
  1361. list[list.length - 1] = {
  1362. ...response.result,
  1363. url: response.result.viewUrl,
  1364. };
  1365. console.log(list);
  1366. voyageBill.value = list;
  1367. }
  1368. let billParams = ref({
  1369. voyageId: route.query.id,
  1370. });
  1371. async function calExpectedArrivalTime() {
  1372. let res = await api.calExpectedArrivalTime({
  1373. voyageId: route.query.id,
  1374. setSailTime: voyage.value.setSailTime,
  1375. });
  1376. if (res.data.status == 0) {
  1377. voyage.value.expectedArrivalTime = res.data.result;
  1378. }
  1379. }
  1380. let isLoadingExcel = ref(false);
  1381. async function downloadExcel() {
  1382. isLoadingExcel.value = true;
  1383. let res = await downloadBlobFile(
  1384. `${url.baseurl}/voyage/exportExcel`,
  1385. { voyageId: route.query.id },
  1386. "船舶跟踪表",
  1387. "post",
  1388. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
  1389. );
  1390. if (res) {
  1391. isLoadingExcel.value = false;
  1392. }
  1393. }
  1394. let isDischargeLoadingExcel = ref(false);
  1395. async function exportDischargeExcel() {
  1396. isDischargeLoadingExcel.value = true;
  1397. let res = await downloadBlobFile(
  1398. `${url.baseurl}/voyage/exportDischargeExcel`,
  1399. { voyageId: route.query.id },
  1400. "卸货记录表",
  1401. "post",
  1402. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
  1403. );
  1404. if (res) {
  1405. isDischargeLoadingExcel.value = false;
  1406. }
  1407. }
  1408. function subStr(str = "") {
  1409. return str.substring(0, 10);
  1410. }
  1411. let truckTableData = ref([]);
  1412. let truckCurrentPage = ref(1);
  1413. let truckTotal = ref(0);
  1414. async function getTruckLoadRecord() {
  1415. let res = await api.getTruckLoadRecord({
  1416. voyageId: route.query.id,
  1417. portId: currentDiscPortId.value,
  1418. currentPage: truckCurrentPage.value,
  1419. size: 10,
  1420. });
  1421. truckTableData.value = res.data.result;
  1422. truckTotal.value = res.data.total;
  1423. }
  1424. function truckPageChange(e) {
  1425. truckCurrentPage.value = e;
  1426. getTruckLoadRecord();
  1427. }
  1428. let truckRecordForm = ref({});
  1429. let isAddTruckRecordVisable = ref(false);
  1430. let truckRecordBillList = ref([]);
  1431. function showTruckRecord(item, index, text) {
  1432. isAddTruckRecordVisable.value = true;
  1433. if (item.file) {
  1434. truckRecordBillList.value[0] = {
  1435. ...item.file,
  1436. url: item.file.viewUrl,
  1437. };
  1438. }
  1439. truckRecordForm.value = { ...item };
  1440. }
  1441. let truckLoadParams = ref({});
  1442. function getTruckLoadBillList() {}
  1443. let blockchainInfo = ref("");
  1444. let billZipLoading = ref(false);
  1445. async function downloadBillZip() {
  1446. billZipLoading.value = true;
  1447. let res = await downloadBlobFile(
  1448. `${url.baseurl}/voyage/exportBillZip`,
  1449. { voyageId: route.query.id },
  1450. "单据文件",
  1451. "post",
  1452. "application/zip"
  1453. );
  1454. billZipLoading.value = false;
  1455. }
  1456. let weatherTableData = ref([]);
  1457. let weatherCurrentPage = ref(1);
  1458. let weatherTotal = ref(0);
  1459. async function getPortWeatherList() {
  1460. let res = await api.getPortWeatherList({
  1461. voyageId: route.query.id,
  1462. portId: currentDiscPortId.value,
  1463. size: 10,
  1464. currentPage: weatherCurrentPage.value,
  1465. });
  1466. weatherTableData.value = res.data.result;
  1467. weatherTotal.value = res.data.total;
  1468. }
  1469. function weatherPageChange(e) {
  1470. weatherCurrentPage.value = e;
  1471. getPortWeatherList();
  1472. }
  1473. let labTableData = ref([]);
  1474. let labTotal = ref(0);
  1475. let labCurrentPage = ref(1);
  1476. async function getLabList() {
  1477. let res = await api.getLabList({
  1478. voyageId: route.query.id,
  1479. portId: currentDiscPortId.value,
  1480. currentPage: labCurrentPage.value,
  1481. size: 10,
  1482. });
  1483. labTableData.value = res.data.result;
  1484. labTotal.value = res.data.total;
  1485. }
  1486. function labPageChange(e) {
  1487. labCurrentPage.value = e;
  1488. getLabList();
  1489. }
  1490. let isAddLabVisable = ref(false);
  1491. let labBillList = ref([]);
  1492. let labForm = ref({});
  1493. function showLab(item) {
  1494. isAddLabVisable.value = true;
  1495. if (item.file) {
  1496. labBillList.value[0] = {
  1497. ...item.file,
  1498. url: item.file.viewUrl,
  1499. };
  1500. }
  1501. labForm.value = { ...item };
  1502. }
  1503. let currentPortId = ref("");
  1504. let currentDiscPortId = ref("");
  1505. let currentDiscPortIndex = ref(0);
  1506. function changeDiscPortTab(e) {
  1507. currentDiscPortIndex.value = e.index;
  1508. currentDiscPortId.value =
  1509. voyage.value.voyageDetails[currentDiscPortIndex.value].portId + "";
  1510. weatherTableData.value = [];
  1511. weatherTotal.value = 0;
  1512. labTableData.value = [];
  1513. labTotal.value = 0;
  1514. dischargeList.value = [];
  1515. total.value = 0;
  1516. truckTableData.value = [];
  1517. truckTotal.value = 0;
  1518. labCurrentPage.value = 1;
  1519. dischargeCurrentPage.value = 1;
  1520. weatherCurrentPage.value = 1;
  1521. truckCurrentPage.value = 1;
  1522. getDischargeList();
  1523. getTruckLoadRecord();
  1524. getLabList();
  1525. getPortWeatherList();
  1526. }
  1527. onMounted(() => {
  1528. getVoyageDetail(true);
  1529. });
  1530. </script>
  1531. <style scoped>
  1532. .map-container {
  1533. width: 100%;
  1534. height: 500px;
  1535. }
  1536. .card-note {
  1537. height: 30px;
  1538. font-size: 12px;
  1539. font-family: PingFangSC-Regular, PingFang SC;
  1540. font-weight: 400;
  1541. color: #777777;
  1542. }
  1543. .medias-box {
  1544. width: 200px;
  1545. height: 200px;
  1546. margin-top: 20px;
  1547. }
  1548. .checkbox-group {
  1549. width: 200px;
  1550. height: 50px;
  1551. margin-top: 20px;
  1552. }
  1553. .medias-content {
  1554. width: 100%;
  1555. height: 600px;
  1556. background: #f7f7f7;
  1557. border-radius: 2px;
  1558. }
  1559. .pic-container {
  1560. width: 100%;
  1561. height: 100%;
  1562. box-sizing: border-box;
  1563. display: flex;
  1564. padding: 30px;
  1565. overflow-x: scroll;
  1566. overflow-y: hidden;
  1567. white-space: nowrap;
  1568. }
  1569. .pic-main {
  1570. position: relative;
  1571. width: 120px;
  1572. }
  1573. .box {
  1574. position: absolute;
  1575. height: 240px;
  1576. width: var(--box-width);
  1577. border: 5px solid #dddddd;
  1578. transition: all 0.5s;
  1579. background: #fff;
  1580. z-index: 10;
  1581. }
  1582. .point {
  1583. position: relative;
  1584. left: 93px;
  1585. top: 258px;
  1586. width: 16px;
  1587. height: 16px;
  1588. background-image: url(../../assets/blue-circle.png);
  1589. }
  1590. .s-line {
  1591. position: absolute;
  1592. left: 100px;
  1593. top: 242px;
  1594. height: 20px;
  1595. border-left: 2px dashed;
  1596. box-sizing: border-box;
  1597. border-color: #ddd;
  1598. }
  1599. .l-line {
  1600. position: relative;
  1601. bottom: 30px;
  1602. left: 111px;
  1603. top: 249px;
  1604. height: 3px;
  1605. width: 100px;
  1606. background-color: #dddddd;
  1607. }
  1608. .bottom-box {
  1609. top: 290px;
  1610. }
  1611. .top210px {
  1612. top: 270px;
  1613. }
  1614. .box:hover {
  1615. transform: scale(1.2);
  1616. }
  1617. .medias-box {
  1618. width: 80px;
  1619. height: 80px;
  1620. margin-top: 10px;
  1621. }
  1622. .card-note {
  1623. height: 30px;
  1624. font-size: 12px;
  1625. font-family: PingFangSC-Regular, PingFang SC;
  1626. font-weight: 400;
  1627. color: #777777;
  1628. padding: 10px 20px;
  1629. }
  1630. .medias-box {
  1631. width: 100%;
  1632. height: 100px;
  1633. margin-top: 20px;
  1634. }
  1635. .checkbox-group {
  1636. width: 180px;
  1637. height: 50px;
  1638. margin-top: 20px;
  1639. }
  1640. .el-checkbox {
  1641. margin: 0;
  1642. }
  1643. .now-box {
  1644. border: 5px solid #0094fe;
  1645. }
  1646. .now-l-line {
  1647. background-color: #0094fe;
  1648. }
  1649. .now-s-line {
  1650. border-color: #97caf6;
  1651. }
  1652. .now-point {
  1653. filter: grayscale(1);
  1654. }
  1655. .info-line-text-table {
  1656. width: 180px !important;
  1657. }
  1658. .upload-plus-icon {
  1659. height: 15%;
  1660. color: rgb(139, 147, 156);
  1661. line-height: 100px;
  1662. font-size: 40px;
  1663. font-weight: 200;
  1664. }
  1665. .upload-text {
  1666. height: 25%;
  1667. color: rgb(139, 147, 156);
  1668. }
  1669. .info-gap {
  1670. width: 40px;
  1671. font-size: 14px;
  1672. overflow: visible;
  1673. white-space: nowrap;
  1674. color: #006ebc;
  1675. cursor: pointer;
  1676. }
  1677. .unit {
  1678. font-size: 14px;
  1679. font-family: PingFangSC-Regular, PingFang SC;
  1680. font-weight: 400;
  1681. color: #353a42;
  1682. line-height: 100%;
  1683. margin: 0 10px;
  1684. }
  1685. </style>