voyageList.vue 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. <template>
  2. <div class="line-container-p24">
  3. <div class="df jcsb aic">
  4. <div class="df aic">
  5. <div
  6. @click="changeVoyageType(0)"
  7. :class="
  8. status == 0
  9. ? 'currentbtn radio-btns left-radius'
  10. : 'radio-btns left-radius'
  11. "
  12. >
  13. 全部航次
  14. </div>
  15. <div
  16. style="border-left: none"
  17. @click="changeVoyageType(1)"
  18. :class="status == 1 ? 'currentbtn radio-btns' : 'radio-btns'"
  19. >
  20. 装货中
  21. </div>
  22. <div
  23. style="border-left: none"
  24. @click="changeVoyageType(2)"
  25. :class="status == 2 ? 'currentbtn radio-btns' : 'radio-btns'"
  26. >
  27. 运输中
  28. </div>
  29. <div
  30. style="border-left: none"
  31. @click="changeVoyageType(3)"
  32. :class="status == 3 ? 'currentbtn radio-btns' : 'radio-btns'"
  33. >
  34. 卸货中
  35. </div>
  36. <div
  37. @click="changeVoyageType(4)"
  38. :class="
  39. status == 4
  40. ? 'currentbtn radio-btns right-radius'
  41. : 'radio-btns right-radius '
  42. "
  43. style="margin-right: 40px; border-left: none"
  44. >
  45. 历史航次
  46. </div>
  47. <!-- <div style="color: #333; margin-right: 10px; font-size: 14px">
  48. 预计到港时间:
  49. </div>
  50. <el-radio-group v-model="sortradio">
  51. <el-radio :label="-1">默认排序</el-radio>
  52. <el-radio :label="0">降序</el-radio>
  53. <el-radio :label="1">升序</el-radio>
  54. </el-radio-group> -->
  55. <el-input
  56. placeholder="请输入船名/MMSI"
  57. prefix-icon="el-icon-search"
  58. v-model="term"
  59. clearable
  60. style="width: 240px"
  61. @keyup.enter.native="getVoyageList()"
  62. ></el-input>
  63. <div class="search-btn" @click="getVoyageList()">查询</div>
  64. </div>
  65. <!-- <div class="cargo-owner-add" @click="voyageAddDialogVisible = true">
  66. 添加航次
  67. </div> -->
  68. <div>
  69. <el-button
  70. type="primary"
  71. size="small"
  72. v-auth="'DOWNLOADVOYAGELIST'"
  73. @click="showExportModal('航次列表')"
  74. >导出航次列表</el-button
  75. >
  76. <el-button
  77. type="primary"
  78. size="small"
  79. v-auth="'MULTDOWNLOADSHIPTRACK'"
  80. @click="showExportModal('航次跟踪')"
  81. >导出航次跟踪</el-button
  82. >
  83. <el-button
  84. type="primary"
  85. size="small"
  86. @click="showExportModal('卸货记录')"
  87. v-auth="'MULTDOWNLOADDISCHARGE'"
  88. >导出卸货记录</el-button
  89. >
  90. <el-button
  91. v-auth="'DOWNLOADFYDI'"
  92. type="primary"
  93. size="small"
  94. @click="downloadFYDI"
  95. >下载FYDI指数</el-button
  96. >
  97. </div>
  98. </div>
  99. <el-dialog
  100. v-model="exportModalVisable"
  101. :title="exportModalTitle"
  102. :close-on-click-modal="false"
  103. width="200px"
  104. >
  105. <div class="df aic jcsb">
  106. <div v-if="exportModalTitle != '航次列表'" class="df aic">
  107. <div class="mr20">请选择月份:</div>
  108. <el-date-picker
  109. v-model="currentMonth"
  110. type="month"
  111. placeholder="请选择年月"
  112. value-format="YYYYMM"
  113. :disabled="isLoadingZip"
  114. />
  115. </div>
  116. <div></div>
  117. <el-button type="primary" @click="exportZip" :loading="isLoadingZip"
  118. >导出{{ exportModalTitle }}</el-button
  119. >
  120. </div>
  121. </el-dialog>
  122. <el-dialog v-model="voyageAddDialogVisible" title="添加航次">
  123. <el-form
  124. :rules="rules"
  125. label-position="right"
  126. label-width="80px"
  127. ref="addVoyageForm"
  128. :model="voyageForm"
  129. :before-close="resetAddVoyageForm"
  130. >
  131. <div class="df ffw">
  132. <!-- <el-form-item prop="voyageName" label="航次名称">
  133. <el-input v-model="voyageForm.voyageName"></el-input>
  134. </el-form-item>
  135. <el-form-item label=""></el-form-item> -->
  136. <el-form-item prop="shipName" label="船舶">
  137. <!-- <el-input v-model="voyageForm.shipOwnerId"></el-input> -->
  138. <el-autocomplete
  139. v-model="voyageForm.shipName"
  140. :fetch-suggestions="searchShip"
  141. placeholder="选择船舶"
  142. @blur="clear('shipId')"
  143. @select="selectShip"
  144. />
  145. </el-form-item>
  146. <el-form-item prop="cargoOwnerName" label="货主">
  147. <el-autocomplete
  148. v-model="voyageForm.cargoOwnerName"
  149. :fetch-suggestions="searchCargoOwner"
  150. @blur="clear('cargoOwnerId')"
  151. placeholder="选择货主"
  152. @select="selectCargoOwner"
  153. />
  154. </el-form-item>
  155. <el-form-item prop="startTime" label="开始时间">
  156. <el-date-picker
  157. v-model="voyageForm.startTime"
  158. type="date"
  159. value-format="YYYY/MM/DD"
  160. placeholder="航次开始时间"
  161. ></el-date-picker>
  162. </el-form-item>
  163. <el-form-item prop="endTime" label="结束时间">
  164. <el-date-picker
  165. v-model="voyageForm.endTime"
  166. type="date"
  167. value-format="YYYY/MM/DD"
  168. placeholder="航次结束时间"
  169. disabled
  170. ></el-date-picker>
  171. </el-form-item>
  172. <el-form-item prop="loadPort" label="装货港">
  173. <el-autocomplete
  174. v-model="voyageForm.loadPort"
  175. :fetch-suggestions="getCol"
  176. @blur="clear('loadPort')"
  177. placeholder="选择装货港"
  178. @select="selectLoadPort"
  179. />
  180. </el-form-item>
  181. <el-form-item prop="dischargeProt" label="卸货港">
  182. <el-autocomplete
  183. v-model="voyageForm.dischargeProt"
  184. :fetch-suggestions="getCol"
  185. @blur="clear('dischargeProt')"
  186. placeholder="选择卸货港"
  187. @select="selectDischargeProt"
  188. />
  189. </el-form-item>
  190. <el-form-item prop="cargo" label="货种">
  191. <el-input v-model="voyageForm.cargo"></el-input>
  192. </el-form-item>
  193. <el-form-item prop="tons" label="吨位">
  194. <el-input v-model="voyageForm.tons"></el-input>
  195. </el-form-item>
  196. </div>
  197. </el-form>
  198. <template #footer>
  199. <span class="dialog-footer">
  200. <el-button @click="resetAddVoyageForm">取消</el-button>
  201. <el-button type="primary" @click="addVoyage">确定</el-button>
  202. </span>
  203. </template>
  204. </el-dialog>
  205. <!-- <div class="mt20">
  206. <p class="mr20 df aic" style="font-size: 14px; color: #333">
  207. 列表筛选:
  208. <el-checkbox
  209. class="ml20"
  210. v-model="selectAllVisable"
  211. label="全选"
  212. size="default"
  213. @change="selectAll"
  214. />
  215. </p>
  216. <el-checkbox
  217. v-model="voyageNameVisable"
  218. label="航次名称"
  219. size="default"
  220. @change="selectSingle"
  221. disabled
  222. />
  223. <el-checkbox
  224. v-model="loadPortVisable"
  225. label="装货港"
  226. size="default"
  227. @change="selectSingle"
  228. />
  229. <el-checkbox
  230. v-model="dischargePortVisable"
  231. label="卸货港"
  232. size="default"
  233. @change="selectSingle"
  234. />
  235. <el-checkbox
  236. v-model="expectedArrivalTimeVisable"
  237. label="预计到港时间"
  238. size="default"
  239. @change="selectSingle"
  240. />
  241. <el-checkbox
  242. v-model="abnormalStatusVisable"
  243. label="航次状态"
  244. size="default"
  245. @change="selectSingle"
  246. />
  247. <el-checkbox
  248. v-model="daysInPortVisable"
  249. label="在港天数"
  250. size="default"
  251. @change="selectSingle"
  252. />
  253. <el-checkbox
  254. v-model="todayPhotoCountVisable"
  255. label="今日照片"
  256. size="default"
  257. @change="selectSingle"
  258. />
  259. <el-checkbox
  260. v-model="cargoVisable"
  261. label="货种"
  262. size="default"
  263. @change="selectSingle"
  264. />
  265. <el-checkbox
  266. v-model="actualLoadTonsVisable"
  267. label="装载吨位"
  268. size="default"
  269. @change="selectSingle"
  270. />
  271. <el-checkbox
  272. v-model="unloadedtonsVisable"
  273. label="已卸货吨位"
  274. size="default"
  275. @change="selectSingle"
  276. />
  277. <el-checkbox
  278. v-model="remainTonsVisable"
  279. label="剩余吨位"
  280. size="default"
  281. @change="selectSingle"
  282. />
  283. <el-checkbox
  284. v-model="hasInsuranceVisable"
  285. label="保险状态"
  286. size="default"
  287. @change="selectSingle"
  288. />
  289. </div> -->
  290. <div
  291. class="df aic jcsb mt20"
  292. style="font-size: 14px; color: #333; width: 1300px"
  293. >
  294. <div>装货港:</div>
  295. <RemoteSearch
  296. api="getCol"
  297. style="width: 100px"
  298. v-model="loadPortFilterStr"
  299. placeholder="装货港"
  300. @selectItem="selectLoadPortFilter($event)"
  301. ></RemoteSearch>
  302. <div>卸货港:</div>
  303. <RemoteSearch
  304. api="getCol"
  305. style="width: 100px"
  306. v-model="discPortFilterStr"
  307. placeholder="卸货港"
  308. @selectItem="selectDiscPortFilter($event)"
  309. ></RemoteSearch>
  310. <div>预计到港时间:</div>
  311. <el-select
  312. style="width: 160px"
  313. v-model="voyageListPostData.isArrived"
  314. placeholder="到港状态"
  315. size="small"
  316. @change="getVoyageList"
  317. >
  318. <el-option label="已到港" :value="0" />
  319. <el-option label="未到港" :value="1" />
  320. </el-select>
  321. <div>航次状态:</div>
  322. <el-select
  323. style="width: 160px"
  324. v-model="voyageListPostData.abnormalStatus"
  325. placeholder="航次状态"
  326. size="small"
  327. @change="getVoyageList"
  328. >
  329. <el-option label="正常" :value="0" />
  330. <el-option label="异常" :value="1" />
  331. </el-select>
  332. <div>货种:</div>
  333. <RemoteSearch
  334. api="getCargoSelect"
  335. style="width: 100px"
  336. v-model="cargoFilterStr"
  337. placeholder="货种"
  338. :params="{
  339. loginAccountId,
  340. status: 2,
  341. }"
  342. @selectItem="selectCargoFilter($event)"
  343. ></RemoteSearch>
  344. <div>保险状态:</div>
  345. <el-select
  346. style="width: 160px"
  347. v-model="voyageListPostData.hasInsurance"
  348. placeholder="保险状态"
  349. size="small"
  350. @change="getVoyageList"
  351. >
  352. <el-option label="未购买" :value="0" />
  353. <el-option label="已购买" :value="1" />
  354. </el-select>
  355. <el-button @click="resetFilter" class="ml20" size="small" type="primary"
  356. >重置</el-button
  357. >
  358. </div>
  359. <el-table
  360. :data="tableData"
  361. stripe
  362. style="width: 100%; margin-top: 12px"
  363. :row-style="rowStyle"
  364. >
  365. <!-- <el-table-column
  366. type="index"
  367. label="序号"
  368. min-width="80"
  369. align="center"
  370. ></el-table-column> -->
  371. <el-table-column
  372. prop="voyageName"
  373. label="航次名称"
  374. v-if="voyageNameVisable"
  375. min-width="140"
  376. align="center"
  377. ></el-table-column>
  378. <el-table-column
  379. prop="loadPort"
  380. label="装货港"
  381. v-if="loadPortVisable"
  382. min-width="90"
  383. align="center"
  384. ></el-table-column>
  385. <el-table-column
  386. prop="dischargePort"
  387. label="卸货港"
  388. v-if="dischargePortVisable"
  389. min-width="80"
  390. align="center"
  391. ></el-table-column>
  392. <!-- <el-table-column
  393. prop="setSailTime"
  394. label="开航时间"
  395. min-width="100"
  396. align="center"
  397. ></el-table-column> -->
  398. <el-table-column
  399. prop="expectedArrivalTime"
  400. label="预计到港时间"
  401. v-if="expectedArrivalTimeVisable"
  402. sortable
  403. min-width="140"
  404. align="center"
  405. >
  406. <template v-slot="scope">
  407. {{ scope.row.arrived ? "已到港" : scope.row.expectedArrivalTime }}
  408. </template>
  409. </el-table-column>
  410. <el-table-column
  411. prop="abnormalStatus"
  412. label="航次状态"
  413. v-if="abnormalStatusVisable"
  414. min-width="80"
  415. align="center"
  416. >
  417. <template v-slot="scope">
  418. {{ scope.row.abnormalStatus == 0 ? "正常" : "异常" }}
  419. </template>
  420. </el-table-column>
  421. <el-table-column
  422. prop="daysInPort"
  423. label="在港天数"
  424. v-if="daysInPortVisable"
  425. sortable
  426. min-width="100"
  427. align="center"
  428. ></el-table-column>
  429. <el-table-column
  430. prop="todayPhotoCount"
  431. label="今日照片"
  432. v-if="todayPhotoCountVisable"
  433. min-width="100"
  434. align="center"
  435. ></el-table-column>
  436. <el-table-column
  437. prop="cargo"
  438. v-if="cargoVisable"
  439. label="货种"
  440. min-width="70"
  441. align="center"
  442. ></el-table-column>
  443. <el-table-column
  444. prop="actualLoadTons"
  445. label="装载吨位"
  446. v-if="actualLoadTonsVisable"
  447. min-width="80"
  448. align="center"
  449. ></el-table-column>
  450. <el-table-column
  451. prop="unloadedtons"
  452. label="已卸货吨位"
  453. v-if="unloadedtonsVisable"
  454. min-width="100"
  455. align="center"
  456. ></el-table-column>
  457. <el-table-column
  458. prop="remainTons"
  459. label="剩余吨位"
  460. v-if="remainTonsVisable"
  461. min-width="80"
  462. align="center"
  463. ></el-table-column>
  464. <!-- <el-table-column
  465. prop="waybillStatus"
  466. sortable
  467. label="签单状态"
  468. min-width="100"
  469. align="center"
  470. >
  471. <template v-slot="scope">
  472. {{
  473. scope.row.waybillStatus == 0
  474. ? ""
  475. : scope.row.waybillStatus == 1
  476. ? "未签单"
  477. : "已签单"
  478. }}
  479. </template>
  480. </el-table-column> -->
  481. <!-- <el-table-column
  482. prop="transStatus"
  483. label="船舶状态"
  484. min-width="100"
  485. align="center"
  486. ></el-table-column> -->
  487. <el-table-column
  488. prop="hasInsurance"
  489. label="保险状态"
  490. v-if="hasInsuranceVisable"
  491. min-width="100"
  492. align="center"
  493. >
  494. <template v-slot="scope">
  495. {{ scope.row.hasInsurance == 0 ? "未购买" : "已购买" }}
  496. </template>
  497. </el-table-column>
  498. <!-- <el-table-column
  499. sortable
  500. prop="createTime"
  501. label="创建时间"
  502. min-width="100"
  503. align="center"
  504. >
  505. <template v-slot="scope">
  506. {{ subTimeStr(scope.row.createTime) }}
  507. </template>
  508. </el-table-column>
  509. <el-table-column
  510. prop="remark"
  511. label="备注"
  512. min-width="100"
  513. align="center"
  514. ></el-table-column> -->
  515. <el-table-column
  516. v-auth="'VOYAGEDETAIL'"
  517. label="操作"
  518. min-width="80"
  519. align="center"
  520. fixed="right"
  521. >
  522. <template v-slot="scope">
  523. <el-button
  524. @click="voyageDetail(scope.row.id, tableData)"
  525. type="text"
  526. size="small"
  527. >
  528. 查看详情
  529. </el-button>
  530. </template>
  531. </el-table-column>
  532. </el-table>
  533. <div style="width: 100%; text-align: right; margin-top: 43px">
  534. <el-pagination
  535. background
  536. layout="prev, pager, next"
  537. :total="total"
  538. @current-change="pageChange"
  539. ></el-pagination>
  540. </div>
  541. </div>
  542. </template>
  543. <script setup>
  544. import { ref, h, reactive, toRefs, onMounted } from "vue";
  545. import { ElNotification, ElMessageBox, ElMessage } from "element-plus";
  546. import store from "../../store";
  547. import router from "../../router";
  548. import md5 from "md5";
  549. import api from "../../apis/fetch";
  550. import _ from "lodash";
  551. import { subTimeStr } from "../../utils/utils";
  552. import downloadBlobFile from "../../utils/downloadBlobFile";
  553. import url from "../../apis/config";
  554. let currentPage = ref(1);
  555. let term = ref("");
  556. let tableData = ref([]);
  557. let total = ref(0);
  558. let status = ref(0);
  559. let loginAccountId = ref("");
  560. let voyageListPostData = ref({});
  561. async function getVoyageList() {
  562. tableData.value = [];
  563. let res = await api.getVoyageList({
  564. ...voyageListPostData.value,
  565. loginAccountId: localStorage.loginAccountId,
  566. cargoOwnerId: localStorage.userId,
  567. shipId: 0,
  568. status: status.value,
  569. term: term.value,
  570. currentPage: currentPage.value,
  571. size: 10,
  572. });
  573. term.value = "";
  574. if (res.data.status == 0) {
  575. tableData.value = res.data.result;
  576. total.value = res.data.total;
  577. } else {
  578. ElNotification({
  579. type: "error",
  580. title: res.data.msg,
  581. });
  582. }
  583. }
  584. function changeVoyageType(s) {
  585. term.value = "";
  586. currentPage.value = 1;
  587. status.value = s;
  588. getVoyageList();
  589. }
  590. async function voyageDetail(id) {
  591. router.push({
  592. path: "/voyage/voyageDetail",
  593. query: {
  594. id,
  595. },
  596. });
  597. }
  598. function pageChange(e) {
  599. currentPage.value = e;
  600. getVoyageList();
  601. }
  602. function goToVoyageAdd() {
  603. router.push({
  604. path: "/voyage/voyageAdd",
  605. });
  606. }
  607. let voyageAddDialogVisible = ref(false);
  608. const rules = reactive({
  609. rules: {
  610. voyageName: [
  611. { required: false, message: "请填写航次名称", trigger: "blur" },
  612. ],
  613. shipName: [{ required: true, message: "请选择船舶", trigger: "blur" }],
  614. cargoOwnerName: [
  615. { required: true, message: "请选择货主", trigger: "blur" },
  616. ],
  617. startTime: [{ required: true, message: "请填写开始时间", trigger: "blur" }],
  618. loadPort: [{ required: true, message: "请填写装货港", trigger: "blur" }],
  619. dischargeProt: [
  620. { required: true, message: "请填写卸货港", trigger: "blur" },
  621. ],
  622. cargo: [{ required: true, message: "请填写货种", trigger: "blur" }],
  623. tons: [{ required: true, message: "请填写吨位", trigger: "blur" }],
  624. },
  625. });
  626. let voyageForm = reactive({
  627. voyageForm: {
  628. voyageName: "",
  629. cargoOwnerId: "",
  630. cargoOwnerName: "",
  631. startTime: "",
  632. endTime: "",
  633. loadPort: "",
  634. dischargeProt: "",
  635. cargo: "",
  636. tons: "",
  637. loadPortId: "",
  638. dischargeProtId: "",
  639. shipId: "",
  640. shipName: "",
  641. },
  642. });
  643. function clear(type) {
  644. setTimeout(() => {
  645. switch (type) {
  646. case "shipId": {
  647. let index = ref(-1);
  648. for (let i in shipsCache.value) {
  649. if (voyageForm.voyageForm.shipName == shipsCache.value[i].shipName) {
  650. index.value = i;
  651. break;
  652. }
  653. }
  654. if (index.value != -1) {
  655. voyageForm.voyageForm.shipId = shipsCache.value[index.value].shipId;
  656. } else {
  657. let b = shipsCache.value.some((item) => {
  658. return (
  659. item.shipId == voyageForm.voyageForm.shipId &&
  660. item.shipName == voyageForm.voyageForm.shipName
  661. );
  662. });
  663. voyageForm.voyageForm["shipId"] = "";
  664. voyageForm.voyageForm["shipName"] = "";
  665. }
  666. break;
  667. }
  668. case "cargoOwnerId": {
  669. let index = ref(-1);
  670. for (let i in cargoOwnersCache.value) {
  671. if (
  672. voyageForm.voyageForm.cargoOwnerName ==
  673. cargoOwnersCache.value[i].userName
  674. ) {
  675. index.value = i;
  676. break;
  677. }
  678. }
  679. if (index.value != -1) {
  680. voyageForm.voyageForm.cargoOwnerId =
  681. cargoOwnersCache.value[index.value].userId;
  682. } else {
  683. let b = cargoOwnersCache.value.some((item) => {
  684. return (
  685. item.userId == voyageForm.voyageForm.cargoOwnerId &&
  686. item.userName == voyageForm.voyageForm.cargoOwnerName
  687. );
  688. });
  689. if (!b) {
  690. voyageForm.voyageForm["cargoOwnerId"] = "";
  691. voyageForm.voyageForm["cargoOwnerName"] = "";
  692. }
  693. }
  694. break;
  695. }
  696. case "loadPort": {
  697. let index = ref(-1);
  698. for (let i in colCache.value) {
  699. if (voyageForm.voyageForm.loadPort == colCache.value[i].value) {
  700. index.value = i;
  701. break;
  702. }
  703. }
  704. if (index.value != -1) {
  705. voyageForm.voyageForm.loadPortId = colCache.value[index.value].key;
  706. } else {
  707. let b = colCache.value.some((item) => {
  708. return (
  709. item.value == voyageForm.voyageForm.loadPort &&
  710. item.key == voyageForm.voyageForm.loadPortId
  711. );
  712. });
  713. if (!b) {
  714. voyageForm.voyageForm["loadPort"] = "";
  715. voyageForm.voyageForm["loadPortId"] = "";
  716. }
  717. }
  718. break;
  719. }
  720. case "dischargeProt": {
  721. let index = ref(-1);
  722. for (let i in colCache.value) {
  723. if (voyageForm.voyageForm.dischargeProt == colCache.value[i].value) {
  724. index.value = i;
  725. break;
  726. }
  727. }
  728. if (index.value != -1) {
  729. voyageForm.voyageForm.dischargeProtId =
  730. colCache.value[index.value].key;
  731. } else {
  732. let b = colCache.value.some((item) => {
  733. return (
  734. item.value == voyageForm.voyageForm.dischargeProt &&
  735. item.key == voyageForm.voyageForm.dischargeProtId
  736. );
  737. });
  738. if (!b) {
  739. voyageForm.voyageForm["dischargeProt"] = "";
  740. voyageForm.voyageForm["dischargeProtId"] = "";
  741. }
  742. }
  743. break;
  744. }
  745. }
  746. }, 200);
  747. }
  748. let addVoyageForm = ref(null);
  749. async function addVoyage() {
  750. addVoyageForm.value.validate(async (valid) => {
  751. if (valid) {
  752. console.log("提交", voyageForm.voyageForm);
  753. let res = await api.addVoyage({
  754. ...voyageForm.voyageForm,
  755. });
  756. if (res.data.status == 0) {
  757. ElNotification({
  758. title: res.data.msg,
  759. type: "success",
  760. });
  761. resetAddVoyageForm();
  762. getVoyageList();
  763. } else {
  764. console.log(res);
  765. ElNotification({
  766. title: res.data.msg,
  767. type: "error",
  768. });
  769. }
  770. } else {
  771. console.log("未提交", voyageForm.voyageForm);
  772. }
  773. });
  774. }
  775. let shipsCache = ref([]);
  776. let colCache = ref([]);
  777. let cargoOwnersCache = ref([]);
  778. const searchShip = _.debounce(
  779. async (queryString, cb) => {
  780. if (!queryString) return;
  781. let res = await api.searchShip({
  782. term: queryString,
  783. });
  784. let ships = [];
  785. if (res.data.status == 0) {
  786. ships = res.data.result;
  787. for (let i of ships) {
  788. i.value = `${i.shipName}`;
  789. }
  790. shipsCache.value = ships;
  791. cb(ships);
  792. }
  793. },
  794. 1000,
  795. { leading: true }
  796. );
  797. const selectShip = (item) => {
  798. voyageForm.voyageForm.shipId = item.shipId;
  799. };
  800. const searchCargoOwner = _.debounce(
  801. async (queryString, cb) => {
  802. if (!queryString) return;
  803. let res = await api.searchUser({
  804. term: queryString,
  805. identity: 2,
  806. });
  807. let cargoOwners = [];
  808. if (res.data.status == 0) {
  809. cargoOwners = res.data.result;
  810. for (let i of cargoOwners) {
  811. i.value = `${i.userName}`;
  812. }
  813. cargoOwnersCache.value = cargoOwners;
  814. cb(cargoOwners);
  815. }
  816. },
  817. 1000,
  818. { leading: true }
  819. );
  820. const selectCargoOwner = (item) => {
  821. voyageForm.voyageForm.cargoOwnerId = item.userId;
  822. };
  823. const getCol = _.debounce(
  824. async (queryString, cb) => {
  825. if (!queryString) return;
  826. let res = await api.getCol({
  827. term: queryString,
  828. });
  829. if (res.data.status == 0) {
  830. colCache.value = [...colCache.value, ...res.data.result];
  831. colCache.value = _.uniqBy(colCache.value, "key");
  832. cb(res.data.result);
  833. }
  834. },
  835. 1000,
  836. { leading: true }
  837. );
  838. const selectLoadPort = (item) => {
  839. voyageForm.voyageForm.loadPortId = item.key;
  840. voyageForm.voyageForm.loadPort = item.value;
  841. };
  842. const selectDischargeProt = (item) => {
  843. voyageForm.voyageForm.dischargeProtId = item.key;
  844. voyageForm.voyageForm.dischargeProt = item.value;
  845. };
  846. function resetAddVoyageForm() {
  847. voyageAddDialogVisible.value = false;
  848. addVoyageForm.value.resetFields();
  849. }
  850. let sortradio = ref(0);
  851. async function downloadFYDI() {
  852. let res0 = await api.getFYFIDownloadUrl({
  853. loginAccountId: localStorage.loginAccountId,
  854. });
  855. let url = res0.data.result;
  856. let a = document.createElement("a");
  857. a.setAttribute("href", url);
  858. a.click();
  859. }
  860. let exportModalVisable = ref(false);
  861. let exportModalTitle = ref("");
  862. let currentMonth = ref("");
  863. function showExportModal(type) {
  864. exportModalVisable.value = true;
  865. exportModalTitle.value = type;
  866. }
  867. let isLoadingZip = ref(false);
  868. async function exportZip() {
  869. if (!currentMonth.value && exportModalTitle.value != "航次列表") return;
  870. isLoadingZip.value = true;
  871. let path = "";
  872. let type = "";
  873. let postData = {
  874. loginAccountId: localStorage.loginAccountId,
  875. };
  876. let title = "";
  877. switch (exportModalTitle.value) {
  878. case "航次列表": {
  879. path = "/voyage/exportListExcel";
  880. type =
  881. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
  882. title = `${exportModalTitle.value}`;
  883. let arr = [];
  884. for (let i of tableData.value) {
  885. arr.push(i.id);
  886. }
  887. postData.voyageIds = arr.join(",");
  888. break;
  889. }
  890. case "航次跟踪": {
  891. path = "/voyage/exportMultExcel";
  892. type = "application/zip";
  893. postData.date = currentMonth.value;
  894. title = `${exportModalTitle.value}${currentMonth.value}`;
  895. break;
  896. }
  897. case "卸货记录": {
  898. path = "/voyage/exportMultDischargeExcel";
  899. type = "application/zip";
  900. postData.date = currentMonth.value;
  901. title = `${exportModalTitle.value}${currentMonth.value}`;
  902. break;
  903. }
  904. }
  905. try {
  906. let res = await downloadBlobFile(
  907. `${url.baseurl}${path}`,
  908. postData,
  909. title,
  910. "post",
  911. type
  912. );
  913. if (res.status == 0) {
  914. ElNotification({
  915. title: "导出成功!",
  916. type: "success",
  917. });
  918. } else {
  919. ElNotification({
  920. title: "暂无数据",
  921. });
  922. }
  923. } catch (error) {
  924. ElNotification({
  925. title: "暂无数据",
  926. });
  927. } finally {
  928. isLoadingZip.value = false;
  929. currentMonth.value = "";
  930. exportModalVisable.value = false;
  931. }
  932. }
  933. function rowStyle({ row }) {
  934. let rowStyle = {};
  935. if (row.daysInPort >= 20 && row.daysInPort < 25) {
  936. rowStyle.color = "#f9ca24";
  937. } else if (row.daysInPort >= 25 && row.daysInPort < 30) {
  938. rowStyle.color = "#f0932b";
  939. } else if (row.daysInPort >= 30) {
  940. rowStyle.color = "#eb4d4b";
  941. }
  942. return rowStyle;
  943. }
  944. let voyageNameVisable = ref(true);
  945. let loadPortVisable = ref(true);
  946. let dischargePortVisable = ref(true);
  947. let expectedArrivalTimeVisable = ref(true);
  948. let abnormalStatusVisable = ref(true);
  949. let daysInPortVisable = ref(true);
  950. let todayPhotoCountVisable = ref(true);
  951. let cargoVisable = ref(true);
  952. let actualLoadTonsVisable = ref(true);
  953. let unloadedtonsVisable = ref(true);
  954. let remainTonsVisable = ref(true);
  955. let hasInsuranceVisable = ref(true);
  956. let selectAllVisable = ref(true);
  957. function selectAll(e) {
  958. loadPortVisable.value = e;
  959. dischargePortVisable.value = e;
  960. expectedArrivalTimeVisable.value = e;
  961. abnormalStatusVisable.value = e;
  962. daysInPortVisable.value = e;
  963. todayPhotoCountVisable.value = e;
  964. cargoVisable.value = e;
  965. actualLoadTonsVisable.value = e;
  966. unloadedtonsVisable.value = e;
  967. remainTonsVisable.value = e;
  968. hasInsuranceVisable.value = e;
  969. }
  970. function selectSingle(e) {
  971. if (!e) {
  972. selectAllVisable.value = e;
  973. }
  974. }
  975. let loadPortFilterStr = ref("");
  976. function selectLoadPortFilter(item) {
  977. voyageListPostData.value.loadPortId = item.key;
  978. getVoyageList();
  979. }
  980. let discPortFilterStr = ref("");
  981. function selectDiscPortFilter(item) {
  982. voyageListPostData.value.discPortId = item.key;
  983. getVoyageList();
  984. }
  985. let cargoFilterStr = ref("");
  986. function selectCargoFilter(item) {
  987. voyageListPostData.value.cargo = item.key;
  988. getVoyageList();
  989. }
  990. function resetFilter() {
  991. loadPortFilterStr.value = "";
  992. discPortFilterStr.value = "";
  993. cargoFilterStr.value = "";
  994. voyageListPostData.value = {};
  995. getVoyageList();
  996. }
  997. onMounted(() => {
  998. getVoyageList();
  999. loginAccountId.value = localStorage.loginAccountId;
  1000. });
  1001. </script>
  1002. <style scoped>
  1003. .search-btn {
  1004. display: inline-block;
  1005. width: 60px;
  1006. height: 32px;
  1007. background: #0094fe;
  1008. border-radius: 2px;
  1009. font-size: 14px;
  1010. font-family: PingFangSC-Regular, PingFang SC;
  1011. font-weight: 400;
  1012. color: #ffffff;
  1013. text-align: center;
  1014. line-height: 32px;
  1015. margin-left: 10px;
  1016. cursor: pointer;
  1017. }
  1018. .cargo-owner-add {
  1019. width: 80px;
  1020. height: 32px;
  1021. border-radius: 2px;
  1022. border: 1px solid #0094fe;
  1023. font-size: 14px;
  1024. font-family: PingFangSC-Regular, PingFang SC;
  1025. font-weight: 400;
  1026. color: #0094fe;
  1027. line-height: 32px;
  1028. text-align: center;
  1029. cursor: pointer;
  1030. }
  1031. :deep().el-dialog {
  1032. width: 560px;
  1033. padding: 20px 50px;
  1034. border-radius: 6px;
  1035. }
  1036. :deep() .el-dialog__title {
  1037. font-size: 18px;
  1038. font-family: PingFangSC-Regular, PingFang SC;
  1039. font-weight: 400;
  1040. color: #0094fe;
  1041. }
  1042. .normal-label {
  1043. font-size: 14px;
  1044. font-family: PingFangSC-Regular, PingFang SC;
  1045. font-weight: 400;
  1046. color: #353a42;
  1047. margin-right: 10px;
  1048. }
  1049. .show-input {
  1050. width: 280px;
  1051. height: 32px;
  1052. background: #ffffff;
  1053. border-radius: 2px;
  1054. border: 1px solid #dee0e3;
  1055. font-size: 14px;
  1056. font-family: PingFangSC-Regular, PingFang SC;
  1057. font-weight: 400;
  1058. color: #333333;
  1059. line-height: 32px;
  1060. padding-left: 12px;
  1061. margin-right: 40px;
  1062. }
  1063. .radio-btns {
  1064. height: 38px;
  1065. width: 70px;
  1066. border: 1px solid #1486f9;
  1067. line-height: 38px;
  1068. text-align: center;
  1069. font-size: 14px;
  1070. font-family: PingFangSC-Regular, PingFang SC;
  1071. font-weight: 400;
  1072. color: #0094fe;
  1073. cursor: pointer;
  1074. }
  1075. .left-radius {
  1076. border-top-left-radius: 19px;
  1077. border-bottom-left-radius: 19px;
  1078. width: 80px;
  1079. }
  1080. .right-radius {
  1081. border-top-right-radius: 19px;
  1082. border-bottom-right-radius: 19px;
  1083. width: 80px;
  1084. }
  1085. .currentbtn {
  1086. background: #1486f9;
  1087. color: #fff;
  1088. }
  1089. .search-btn {
  1090. display: inline-block;
  1091. width: 60px;
  1092. height: 38px;
  1093. background: #0094fe;
  1094. border-radius: 2px;
  1095. font-size: 14px;
  1096. font-family: PingFangSC-Regular, PingFang SC;
  1097. font-weight: 400;
  1098. color: #ffffff;
  1099. text-align: center;
  1100. line-height: 38px;
  1101. margin-left: 10px;
  1102. cursor: pointer;
  1103. }
  1104. .voyage-add {
  1105. width: 80px;
  1106. height: 36px;
  1107. border-radius: 2px;
  1108. border: 1px solid #0094fe;
  1109. font-size: 14px;
  1110. font-family: PingFangSC-Regular, PingFang SC;
  1111. font-weight: 400;
  1112. color: #0094fe;
  1113. line-height: 36px;
  1114. text-align: center;
  1115. cursor: pointer;
  1116. }
  1117. :deep() .el-dialog {
  1118. width: 800px;
  1119. }
  1120. :deep() .el-form-item {
  1121. margin-right: 22px;
  1122. width: 300px;
  1123. }
  1124. :deep() .el-autocomplete {
  1125. width: 220px;
  1126. }
  1127. .el-radio {
  1128. margin-right: 10px;
  1129. }
  1130. .el-radio:last-child {
  1131. margin-right: 20px;
  1132. }
  1133. </style>