ShipInfo.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. <template>
  2. <div>
  3. <div class="container-title">船舶信息</div>
  4. <div
  5. class="pt10 bgf df jcsb pr20"
  6. v-if="route.name == 'shipOwnerDetail' || route.name == 'shipDetail'"
  7. style="max-width: 1200px"
  8. >
  9. <el-button-group class="mr20" v-if="route.name == 'shipOwnerDetail'">
  10. <el-button
  11. v-for="(item, index) in shipInfos"
  12. :key="item.code"
  13. @click="currentIndex = index"
  14. :disabled="!shipInfoDisabled"
  15. v-show="item.code"
  16. :type="index == currentIndex ? 'primary' : ''"
  17. >
  18. {{ item.shipname || "新增船舶" }}
  19. </el-button>
  20. </el-button-group>
  21. <div></div>
  22. <div class="df">
  23. <div class="df" v-if="shipInfos[currentIndex].code">
  24. <el-button v-if="shipInfoDisabled" type="primary" @click="showUpdate">
  25. 更新船舶基础信息
  26. </el-button>
  27. <el-button
  28. v-if="!shipInfoDisabled"
  29. type="primary"
  30. @click="confirmUpdate"
  31. >
  32. 确认更新
  33. </el-button>
  34. <el-button
  35. v-if="!shipInfoDisabled"
  36. type="primary"
  37. @click="cancelUpdate"
  38. >
  39. 取消更新
  40. </el-button>
  41. <el-button
  42. v-if="route.name == 'shipOwnerDetail'"
  43. @click="deleteShip(currentIndex)"
  44. type="primary"
  45. class="mr20"
  46. >
  47. 删除当前船舶
  48. </el-button>
  49. </div>
  50. <div class="df" v-if="route.name == 'shipOwnerDetail'">
  51. <el-button
  52. v-if="shipInfos.length == 0 || shipInfos[currentIndex].code"
  53. @click="addShip()"
  54. type="primary"
  55. >
  56. 新增船舶
  57. </el-button>
  58. <div v-else>
  59. <el-button
  60. v-if="shipInfos.length > 1"
  61. @click="cancelAdd()"
  62. type="primary"
  63. >
  64. 取消新增船舶
  65. </el-button>
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. <div class="line-container-p24">
  71. <div class="line">
  72. <div class="info-line">
  73. <div class="info-line-title">认证状态</div>
  74. <el-tag
  75. v-if="shipInfos[currentIndex].hhdAuthStatus === 1"
  76. type="success"
  77. size="large"
  78. >
  79. 已认证
  80. </el-tag>
  81. <el-button
  82. v-if="shipInfos[currentIndex].hhdAuthStatus === 0"
  83. type="primary"
  84. @click="authShip()"
  85. >
  86. 船员认证
  87. </el-button>
  88. </div>
  89. </div>
  90. <div class="line">
  91. <div class="info-line">
  92. <div class="info-line-title">
  93. <span class="red">*</span>
  94. 船名
  95. </div>
  96. <el-input
  97. class="info-line-text"
  98. v-model="shipInfos[currentIndex].shipname"
  99. :disabled="shipInfoDisabled"
  100. ></el-input>
  101. <view class="unit"></view>
  102. </div>
  103. <div class="info-line">
  104. <div class="info-line-title">
  105. <span class="red">*</span>
  106. MMSI
  107. </div>
  108. <el-input
  109. class="info-line-text"
  110. v-model="shipInfos[currentIndex].mmsi"
  111. :disabled="
  112. shipInfoDisabled ||
  113. !!shipInfos[currentIndex].code ||
  114. !!shipInfos[currentIndex].shipId
  115. "
  116. @blur="searchShip($event, currentIndex)"
  117. ></el-input>
  118. </div>
  119. </div>
  120. <div class="line">
  121. <div class="info-line">
  122. <div class="info-line-title">
  123. <span class="red">*</span>
  124. 船员姓名
  125. </div>
  126. <el-input
  127. class="info-line-text"
  128. v-model="shipInfos[currentIndex].contentShipOwnerName"
  129. :disabled="shipInfoDisabled"
  130. ></el-input>
  131. <view class="unit"></view>
  132. </div>
  133. <div class="info-line">
  134. <div class="info-line-title">
  135. <span class="red">*</span>
  136. 船员手机号
  137. </div>
  138. <el-input
  139. class="info-line-text"
  140. v-model="shipInfos[currentIndex].contentShipOwnerPhone"
  141. :disabled="shipInfoDisabled"
  142. ></el-input>
  143. <view class="unit"></view>
  144. </div>
  145. </div>
  146. <div class="line">
  147. <div class="info-line">
  148. <div class="info-line-title">船籍</div>
  149. <el-select
  150. style="width: 240px"
  151. v-model="shipInfos[currentIndex].registryProvince"
  152. placeholder="请选择船籍"
  153. :disabled="shipInfoDisabled"
  154. >
  155. <el-option
  156. v-for="item in provinceOptions"
  157. :key="item.value"
  158. :label="item.label"
  159. :value="item.value"
  160. />
  161. </el-select>
  162. </div>
  163. </div>
  164. <div class="line">
  165. <div class="info-line">
  166. <div class="info-line-title">船长</div>
  167. <el-input
  168. class="info-line-text"
  169. v-model="shipInfos[currentIndex].length"
  170. :disabled="shipInfoDisabled"
  171. ></el-input>
  172. <view class="unit">米</view>
  173. </div>
  174. <div class="info-line">
  175. <div class="info-line-title">船宽</div>
  176. <el-input
  177. class="info-line-text"
  178. v-model="shipInfos[currentIndex].breadth"
  179. :disabled="shipInfoDisabled"
  180. ></el-input>
  181. <view class="unit">米</view>
  182. </div>
  183. </div>
  184. <div class="line">
  185. <div class="info-line">
  186. <div class="info-line-title">载货吨位</div>
  187. <el-input
  188. class="info-line-text"
  189. v-model="shipInfos[currentIndex].loadTons"
  190. :disabled="shipInfoDisabled"
  191. ></el-input>
  192. <view class="unit">吨</view>
  193. </div>
  194. <div class="info-line">
  195. <div class="info-line-title">船龄</div>
  196. <el-input
  197. class="info-line-text"
  198. v-model="shipInfos[currentIndex].age"
  199. :disabled="shipInfoDisabled"
  200. ></el-input>
  201. <view class="unit">年</view>
  202. </div>
  203. </div>
  204. <div class="line">
  205. <div class="info-line">
  206. <div class="info-line-title">满载吃水</div>
  207. <el-input
  208. class="info-line-text"
  209. v-model="shipInfos[currentIndex].draught"
  210. :disabled="shipInfoDisabled"
  211. ></el-input>
  212. <view class="unit">米</view>
  213. </div>
  214. <div class="info-line">
  215. <div class="info-line-title">吨位(总吨)</div>
  216. <el-input
  217. class="info-line-text"
  218. v-model="shipInfos[currentIndex].tonnage"
  219. :disabled="shipInfoDisabled"
  220. ></el-input>
  221. <view class="unit">吨</view>
  222. </div>
  223. </div>
  224. <div class="line">
  225. <div class="info-line">
  226. <div class="info-line-title">主机功率</div>
  227. <el-input
  228. class="info-line-text"
  229. v-model="shipInfos[currentIndex].monitorRate"
  230. :disabled="shipInfoDisabled"
  231. ></el-input>
  232. <view class="unit">千瓦</view>
  233. </div>
  234. <div class="info-line">
  235. <div class="info-line-title">南京报备</div>
  236. <el-switch
  237. v-model="shipInfos[currentIndex].nanjingReport"
  238. size="large"
  239. active-text="已报备"
  240. :active-value="1"
  241. inactive-text="未报备"
  242. :inactive-value="0"
  243. :disabled="shipInfoDisabled"
  244. />
  245. </div>
  246. </div>
  247. <div class="line">
  248. <div class="info-line">
  249. <div class="info-line-title">三峡报备</div>
  250. <el-switch
  251. v-model="shipInfos[currentIndex].sanxiaReport"
  252. size="large"
  253. active-text="已报备"
  254. :active-value="1"
  255. inactive-text="未报备"
  256. :inactive-value="0"
  257. :disabled="shipInfoDisabled"
  258. />
  259. </div>
  260. </div>
  261. </div>
  262. <div style="max-width: 1200px">
  263. <div class="container-title">船舶证书</div>
  264. <div
  265. v-for="(item, index) in shipInfos[currentIndex].shipCerts"
  266. :key="item.title"
  267. style="background: #fff"
  268. class="pt20"
  269. >
  270. <div v-if="item.type == 5" class="container-title fs18 pt10 pb10">
  271. 船舶保险
  272. </div>
  273. <div class="df aic pl40 pb20">
  274. <div class="c6 fs16 mr30">
  275. {{ item.typeName }}
  276. </div>
  277. </div>
  278. <div class="ml50 mb20 c7 fs14" v-if="item.type != 0">
  279. <div
  280. class="df aic mb10"
  281. v-for="(item1, index1) in item.certValids"
  282. :key="item.id"
  283. >
  284. <div class="mr10" style="width: 140px">{{ item1.typeName }}</div>
  285. <el-date-picker
  286. style="width: 140px; font-size: 13px"
  287. v-model="item1.startValidTime"
  288. @change="changeDate($event, item, item1)"
  289. type="date"
  290. placeholder="有效期开始时间"
  291. value-format="YYYY/MM/DD"
  292. format="YYYY/MM/DD"
  293. />
  294. <div style="margin: 0 4px">-</div>
  295. <el-date-picker
  296. style="width: 140px; font-size: 13px"
  297. v-model="item1.endValidTime"
  298. @change="changeDate($event, item, item1)"
  299. type="date"
  300. placeholder="有效期结束时间"
  301. value-format="YYYY/MM/DD"
  302. format="YYYY/MM/DD"
  303. />
  304. </div>
  305. </div>
  306. <div class="df">
  307. <Uploader
  308. class="ml50 pb20"
  309. :uploaderId="'certsId' + 'country'"
  310. :params="
  311. shipInfos[currentIndex].code
  312. ? {
  313. ...updateParams,
  314. shipCode: shipInfos[currentIndex].code,
  315. type: item.type,
  316. }
  317. : addParams
  318. "
  319. :actionUrl="
  320. shipInfos[currentIndex].code
  321. ? store.state.shipCertUpdateUrl
  322. : store.state.addCertsUrl
  323. "
  324. :disabled="disabled"
  325. :fileList="item.certs"
  326. @onUploadFileList="uploadSuccess($event, index)"
  327. @onRemoveFileList="removeSuccess($event, index)"
  328. ></Uploader>
  329. </div>
  330. </div>
  331. <div
  332. v-if="!shipInfos[currentIndex].code"
  333. class="p30 mb30 df jcfe"
  334. style="background: #fff"
  335. >
  336. <el-button :loading="isSubmitLoading" @click="submit" type="primary">
  337. {{ isSubmitLoading ? "正在添加" : "添加船舶" }}
  338. </el-button>
  339. </div>
  340. </div>
  341. </div>
  342. </template>
  343. <script setup>
  344. import { defineComponent, computed, ref, onMounted, watch } from "vue";
  345. import { ElMessage } from "element-plus";
  346. import api from "../apis/fetch";
  347. import _ from "lodash";
  348. import store from "../store";
  349. import { useRoute } from "vue-router";
  350. import router from "../router";
  351. import { confirm } from "../utils/utils";
  352. const route = useRoute();
  353. const props = defineProps({
  354. certsId: {
  355. type: String,
  356. default: "cert",
  357. },
  358. disabled: {
  359. type: Boolean,
  360. default: false,
  361. },
  362. shipInfos: {
  363. type: Array,
  364. default: [{}],
  365. },
  366. shipOwnerId: [String, Number],
  367. });
  368. let currentIndex = ref(0);
  369. const emit = defineEmits(["submit"]);
  370. function initCerts(certs) {
  371. console.log(certs);
  372. }
  373. let updateParams = ref({
  374. loginAccountId: localStorage.loginAccountId,
  375. });
  376. let addParams = ref({
  377. loginAccountId: localStorage.loginAccountId,
  378. });
  379. // function uploadSuccess(list, index) {
  380. function uploadSuccess({ response, file, list }, index) {
  381. if (response.status == 0) {
  382. let { key, fileKey, viewUrl, downloadUrl, id } = response.result;
  383. props.shipInfos[currentIndex.value].shipCerts[index].certs.push({
  384. fileKey: fileKey || key,
  385. viewUrl,
  386. downloadUrl,
  387. id,
  388. url: viewUrl,
  389. });
  390. }
  391. }
  392. async function removeSuccess({ file, fileIndex }, index) {
  393. if (props.shipInfos[currentIndex.value].code) {
  394. let { data } = await api.deleteShipCert({ shipCertId: file.id });
  395. if (data.status == 0) {
  396. ElMessage({
  397. message: "删除成功!",
  398. type: "success",
  399. });
  400. props.shipInfos[currentIndex.value].shipCerts[index].certs.splice(
  401. fileIndex,
  402. 1
  403. );
  404. }
  405. } else {
  406. props.shipInfos[currentIndex.value].shipCerts[index].certs.splice(
  407. fileIndex,
  408. 1
  409. );
  410. }
  411. }
  412. async function changeDate(e, item, item1) {
  413. if (props.shipInfos[currentIndex.value].code) {
  414. let { data } = await api.updateShipCertValid({
  415. shipCode: props.shipInfos[currentIndex.value].code,
  416. type: item.type,
  417. validType: item1.type,
  418. startValidTime: item1.startValidTime,
  419. endValidTime: item1.endValidTime,
  420. });
  421. if (data.status == 0) {
  422. ElMessage({
  423. message: "更新成功!",
  424. type: "success",
  425. });
  426. }
  427. }
  428. }
  429. function getShipCerts() {
  430. return shipCerts.value;
  431. }
  432. async function searchShip(e) {
  433. if (e.target.value.length != 9) return;
  434. const loading = ElLoading.service({
  435. lock: true,
  436. text: "正在匹配船舶...",
  437. background: "rgba(0, 0, 0, 0.7)",
  438. });
  439. let { data } = await api.searchShip({
  440. mmsi: e.target.value,
  441. });
  442. loading.close();
  443. if (data.status == 0) {
  444. data.result.shipCerts[0].typeName = "船舶主要项目页";
  445. data.result.shipCerts[1].typeName = "船舶国籍证书";
  446. data.result.shipCerts[2].typeName = "内河船舶适航证书";
  447. data.result.shipCerts[3].typeName = "船舶营运证书";
  448. data.result.shipCerts[4].typeName = "内河船舶最低安全配员证书";
  449. data.result.shipCerts[5].typeName = "船舶保险";
  450. for (let i of data.result.shipCerts) {
  451. for (let j of i.certs) {
  452. j.url = j.viewUrl;
  453. }
  454. }
  455. data.result.disabled = false;
  456. if (props.shipInfos[currentIndex.value].shipname)
  457. data.result.shipname = props.shipInfos[currentIndex.value].shipname;
  458. props.shipInfos[currentIndex.value] = data.result;
  459. }
  460. }
  461. function deleteShip(index) {
  462. ElMessageBox.confirm("确认删除船舶?", "提示", {
  463. confirmButtonText: "确认",
  464. cancelButtonText: "取消",
  465. type: "warning",
  466. })
  467. .then(async () => {
  468. console.log(index);
  469. let { data } = await api.deleteShip({
  470. shipCode: props.shipInfos[index].code,
  471. });
  472. if (data.status == 0) {
  473. ElMessage({
  474. type: "success",
  475. message: "删除成功",
  476. });
  477. props.shipInfos.splice(index, 1);
  478. currentIndex.value = 0;
  479. }
  480. })
  481. .catch(() => {});
  482. }
  483. let cacheIndex = -1;
  484. async function addShip(item) {
  485. cacheIndex = _.cloneDeep(currentIndex.value);
  486. shipInfoDisabled.value = false;
  487. let { data } = await api.getAddShipCerts({});
  488. let initShipInfo = {
  489. shipId: 0,
  490. disabled: false,
  491. shipCerts: data.result,
  492. };
  493. if (
  494. props.shipInfos.length &&
  495. props.shipInfos[props.shipInfos.length - 1].code
  496. ) {
  497. props.shipInfos.push(initShipInfo);
  498. } else {
  499. props.shipInfos[props.shipInfos.length - 1] = initShipInfo;
  500. }
  501. currentIndex.value = props.shipInfos.length - 1;
  502. }
  503. function cancelAdd() {
  504. currentIndex.value = _.cloneDeep(cacheIndex);
  505. shipInfoDisabled.value = true;
  506. }
  507. let isSubmitLoading = ref(false);
  508. async function submit() {
  509. if (!props.shipInfos[currentIndex.value].shipname) {
  510. ElMessage({
  511. type: "warning",
  512. message: "请填写船舶名称",
  513. });
  514. return;
  515. }
  516. if (!props.shipInfos[currentIndex.value].mmsi) {
  517. ElMessage({
  518. type: "warning",
  519. message: "请填写船舶MMSI",
  520. });
  521. return;
  522. }
  523. if (!props.shipInfos[currentIndex.value].contentShipOwnerName) {
  524. ElMessage({
  525. type: "warning",
  526. message: "请填写船员姓名",
  527. });
  528. return;
  529. }
  530. if (!props.shipInfos[currentIndex.value].contentShipOwnerPhone) {
  531. ElMessage({
  532. type: "warning",
  533. message: "请填写船员手机号",
  534. });
  535. return;
  536. }
  537. isSubmitLoading.value = true;
  538. let { data } = await api.addShip({
  539. ...props.shipInfos[currentIndex.value],
  540. shipOwnerId: props.shipOwnerId,
  541. });
  542. isSubmitLoading.value = false;
  543. store.commit("removeAlive", "shipOwnerList");
  544. if (data.status == 0) {
  545. ElMessage({
  546. type: "success",
  547. message: data.msg,
  548. duration: 1500,
  549. });
  550. router.replace("/shipOwnerManage/shipOwnerList");
  551. } else {
  552. ElMessage({
  553. type: "warning",
  554. message: data.msg,
  555. duration: 2500,
  556. });
  557. }
  558. }
  559. let shipInfoDisabled = ref(true);
  560. let cacheInfo = ref({});
  561. function showUpdate() {
  562. cacheInfo.value = _.cloneDeep(props.shipInfos[currentIndex.value]);
  563. shipInfoDisabled.value = false;
  564. }
  565. async function confirmUpdate() {
  566. let postData = props.shipInfos[currentIndex.value];
  567. postData.shipCode = postData.code;
  568. let { data } = await api.updateShip(postData);
  569. if (data.status == 0) {
  570. ElMessage({
  571. message: data.msg,
  572. type: "success",
  573. });
  574. shipInfoDisabled.value = true;
  575. } else {
  576. ElMessage({
  577. message: data.msg,
  578. type: "error",
  579. });
  580. }
  581. }
  582. function cancelUpdate() {
  583. props.shipInfos[currentIndex.value] = _.cloneDeep(cacheInfo.value);
  584. shipInfoDisabled.value = true;
  585. }
  586. function changeDisable(b) {
  587. shipInfoDisabled.value = b;
  588. }
  589. const provinceOptions = ref([]);
  590. async function getProvinceSelect() {
  591. let { data } = await api.getProvinceSelect();
  592. if (data.status === 0) {
  593. provinceOptions.value = data.result;
  594. } else {
  595. provinceOptions.value = [];
  596. }
  597. }
  598. async function authShip() {
  599. if (!(await confirm("确认认证船舶?"))) return;
  600. let { data } = await api.authShip({
  601. shipCode: route.query.shipCode,
  602. });
  603. if (data.status === 0) {
  604. ElMessage({
  605. type: "success",
  606. message: data.msg,
  607. });
  608. props.shipInfos[currentIndex.value].hhdAuthStatus = 1;
  609. } else {
  610. ElMessage({
  611. type: "error",
  612. message: data.msg,
  613. });
  614. }
  615. }
  616. defineExpose({
  617. initCerts,
  618. getShipCerts,
  619. changeDisable,
  620. });
  621. onMounted(() => {
  622. getProvinceSelect();
  623. });
  624. </script>
  625. <style scoped>
  626. .unit {
  627. width: 40px;
  628. text-align: center;
  629. color: #555;
  630. }
  631. </style>