ShipInfo.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. <template>
  2. <div>
  3. <div class="container-title">船舶信息</div>
  4. <div
  5. class="pl50 pt30 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">
  74. <span class="red">*</span>
  75. 船名
  76. </div>
  77. <el-input
  78. class="info-line-text"
  79. v-model="shipInfos[currentIndex].shipname"
  80. :disabled="shipInfoDisabled"
  81. ></el-input>
  82. <view class="unit"></view>
  83. </div>
  84. <div class="info-line">
  85. <div class="info-line-title">MMSI</div>
  86. <el-input
  87. class="info-line-text"
  88. v-model="shipInfos[currentIndex].mmsi"
  89. :disabled="
  90. shipInfoDisabled ||
  91. !!shipInfos[currentIndex].code ||
  92. !!shipInfos[currentIndex].shipId
  93. "
  94. @blur="searchShip($event, currentIndex)"
  95. ></el-input>
  96. </div>
  97. </div>
  98. <div class="line">
  99. <div class="info-line">
  100. <div class="info-line-title">
  101. <span class="red">*</span>
  102. 联系人姓名
  103. </div>
  104. <el-input
  105. class="info-line-text"
  106. v-model="shipInfos[currentIndex].contentShipOwnerName"
  107. :disabled="shipInfoDisabled"
  108. ></el-input>
  109. <view class="unit"></view>
  110. </div>
  111. <div class="info-line">
  112. <div class="info-line-title">
  113. <span class="red">*</span>
  114. 联系人手机号
  115. </div>
  116. <el-input
  117. class="info-line-text"
  118. v-model="shipInfos[currentIndex].contentShipOwnerPhone"
  119. :disabled="shipInfoDisabled"
  120. ></el-input>
  121. <view class="unit"></view>
  122. </div>
  123. </div>
  124. <div class="line">
  125. <div class="info-line">
  126. <div class="info-line-title">船长</div>
  127. <el-input
  128. class="info-line-text"
  129. v-model="shipInfos[currentIndex].length"
  130. :disabled="shipInfoDisabled"
  131. ></el-input>
  132. <view class="unit">米</view>
  133. </div>
  134. <div class="info-line">
  135. <div class="info-line-title">船宽</div>
  136. <el-input
  137. class="info-line-text"
  138. v-model="shipInfos[currentIndex].breadth"
  139. :disabled="shipInfoDisabled"
  140. ></el-input>
  141. <view class="unit">米</view>
  142. </div>
  143. </div>
  144. <div class="line">
  145. <div class="info-line">
  146. <div class="info-line-title">载货吨位</div>
  147. <el-input
  148. class="info-line-text"
  149. v-model="shipInfos[currentIndex].loadTons"
  150. :disabled="shipInfoDisabled"
  151. ></el-input>
  152. <view class="unit">吨</view>
  153. </div>
  154. <div class="info-line">
  155. <div class="info-line-title">船龄</div>
  156. <el-input
  157. class="info-line-text"
  158. v-model="shipInfos[currentIndex].age"
  159. :disabled="shipInfoDisabled"
  160. ></el-input>
  161. <view class="unit">年</view>
  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].draught"
  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].tonnage"
  179. :disabled="shipInfoDisabled"
  180. ></el-input>
  181. <view class="unit">吨</view>
  182. </div>
  183. </div>
  184. </div>
  185. <div style="max-width: 1200px">
  186. <div class="container-title">船舶证书</div>
  187. <div
  188. v-for="(item, index) in shipInfos[currentIndex].shipCerts"
  189. :key="item.title"
  190. style="background: #fff"
  191. class="pt20"
  192. >
  193. <div v-if="item.type == 5" class="container-title fs18 pt10 pb10">
  194. 船舶保险
  195. </div>
  196. <div class="df aic pl40 pb20">
  197. <div class="c6 fs16 mr30">{{ item.typeName }}</div>
  198. </div>
  199. <div class="ml50 mb20 c7 fs14" v-if="item.type != 0">
  200. <div
  201. class="df aic mb10"
  202. v-for="(item1, index1) in item.certValids"
  203. :key="item.id"
  204. >
  205. <div class="mr10">{{ item1.typeName }}</div>
  206. <el-date-picker
  207. style="width: 140px; font-size: 13px"
  208. v-model="item1.startValidTime"
  209. @change="changeDate($event, item, item1)"
  210. type="date"
  211. placeholder="有效期开始时间"
  212. value-format="YYYY/MM/DD"
  213. format="YYYY/MM/DD"
  214. />
  215. <div style="margin: 0 4px">-</div>
  216. <el-date-picker
  217. style="width: 140px; font-size: 13px"
  218. v-model="item1.endValidTime"
  219. @change="changeDate($event, item, item1)"
  220. type="date"
  221. placeholder="有效期结束时间"
  222. value-format="YYYY/MM/DD"
  223. format="YYYY/MM/DD"
  224. />
  225. </div>
  226. </div>
  227. <div class="df">
  228. <Uploader
  229. class="ml50 pb20"
  230. :uploaderId="'certsId' + 'country'"
  231. :params="
  232. shipInfos[currentIndex].code
  233. ? {
  234. ...updateParams,
  235. shipCode: shipInfos[currentIndex].code,
  236. type: item.type,
  237. }
  238. : addParams
  239. "
  240. :actionUrl="
  241. shipInfos[currentIndex].code
  242. ? store.state.updateCertsUrl
  243. : store.state.addCertsUrl
  244. "
  245. :disabled="disabled"
  246. :fileList="item.certs"
  247. @onUploadFileList="uploadSuccess($event, index)"
  248. @onRemoveFileList="removeSuccess($event, index)"
  249. ></Uploader>
  250. </div>
  251. </div>
  252. <div
  253. v-if="!shipInfos[currentIndex].code"
  254. class="p30 mb30 df jcfe"
  255. style="background: #fff"
  256. >
  257. <el-button :loading="isSubmitLoading" @click="submit" type="primary">
  258. {{ isSubmitLoading ? "正在添加" : "添加船舶" }}
  259. </el-button>
  260. </div>
  261. </div>
  262. </div>
  263. </template>
  264. <script setup>
  265. import { defineComponent, computed, ref, onMounted, watch } from "vue";
  266. import { ElMessage } from "element-plus";
  267. import api from "../apis/fetch";
  268. import _ from "lodash";
  269. import store from "../store";
  270. import { useRoute } from "vue-router";
  271. import router from "../router";
  272. const route = useRoute();
  273. const props = defineProps({
  274. certsId: {
  275. type: String,
  276. default: "cert",
  277. },
  278. disabled: {
  279. type: Boolean,
  280. default: false,
  281. },
  282. shipInfos: {
  283. type: Array,
  284. default: [{}],
  285. },
  286. shipOwnerId: [String, Number],
  287. });
  288. let currentIndex = ref(0);
  289. const emit = defineEmits(["submit"]);
  290. function initCerts(certs) {
  291. console.log(certs);
  292. }
  293. let updateParams = ref({
  294. loginAccountId: localStorage.loginAccountId,
  295. });
  296. let addParams = ref({
  297. loginAccountId: localStorage.loginAccountId,
  298. });
  299. // function uploadSuccess(list, index) {
  300. function uploadSuccess({ response, file, list }, index) {
  301. if (response.status == 0) {
  302. let { key, fileKey, viewUrl, downloadUrl, id } = response.result;
  303. props.shipInfos[currentIndex.value].shipCerts[index].certs.push({
  304. fileKey: fileKey || key,
  305. viewUrl,
  306. downloadUrl,
  307. id,
  308. url: viewUrl,
  309. });
  310. }
  311. }
  312. async function removeSuccess({ file, fileIndex }, index) {
  313. if (props.shipInfos[currentIndex.value].code) {
  314. let { data } = await api.deleteShipCert({ shipCertId: file.id });
  315. if (data.status == 0) {
  316. ElMessage({
  317. message: "删除成功!",
  318. type: "success",
  319. });
  320. props.shipInfos[currentIndex.value].shipCerts[index].certs.splice(
  321. fileIndex,
  322. 1
  323. );
  324. }
  325. } else {
  326. props.shipInfos[currentIndex.value].shipCerts[index].certs.splice(
  327. fileIndex,
  328. 1
  329. );
  330. }
  331. }
  332. async function changeDate(e, item, item1) {
  333. if (props.shipInfos[currentIndex.value].code) {
  334. let { data } = await api.updateShipCertValid({
  335. shipCode: props.shipInfos[currentIndex.value].code,
  336. type: item.type,
  337. validType: item1.type,
  338. startValidTime: item1.startValidTime,
  339. endValidTime: item1.endValidTime,
  340. });
  341. if (data.status == 0) {
  342. ElMessage({
  343. message: "更新成功!",
  344. type: "success",
  345. });
  346. }
  347. }
  348. }
  349. function getShipCerts() {
  350. return shipCerts.value;
  351. }
  352. async function searchShip(e) {
  353. if (e.target.value.length != 9) return;
  354. const loading = ElLoading.service({
  355. lock: true,
  356. text: "正在匹配船舶...",
  357. background: "rgba(0, 0, 0, 0.7)",
  358. });
  359. let { data } = await api.searchShip({
  360. mmsi: e.target.value,
  361. });
  362. loading.close();
  363. if (data.status == 0) {
  364. data.result.shipCerts[0].typeName = "船舶主要项目页";
  365. data.result.shipCerts[1].typeName = "船舶国籍证书";
  366. data.result.shipCerts[2].typeName = "内河船舶适航证书";
  367. data.result.shipCerts[3].typeName = "船舶营运证书";
  368. data.result.shipCerts[4].typeName = "内河船舶最低安全配员证书";
  369. data.result.shipCerts[5].typeName = "船舶保险";
  370. for (let i of data.result.shipCerts) {
  371. for (let j of i.certs) {
  372. j.url = j.viewUrl;
  373. }
  374. }
  375. data.result.disabled = false;
  376. if (props.shipInfos[currentIndex.value].shipname)
  377. data.result.shipname = props.shipInfos[currentIndex.value].shipname;
  378. props.shipInfos[currentIndex.value] = data.result;
  379. }
  380. }
  381. function deleteShip(index) {
  382. ElMessageBox.confirm("确认删除船舶?", "提示", {
  383. confirmButtonText: "确认",
  384. cancelButtonText: "取消",
  385. type: "warning",
  386. })
  387. .then(async () => {
  388. console.log(index);
  389. let { data } = await api.deleteShip({
  390. shipCode: props.shipInfos[index].code,
  391. });
  392. if (data.status == 0) {
  393. ElMessage({
  394. type: "success",
  395. message: "删除成功",
  396. });
  397. props.shipInfos.splice(index, 1);
  398. currentIndex.value = 0;
  399. }
  400. })
  401. .catch(() => {});
  402. }
  403. let cacheIndex = -1;
  404. async function addShip(item) {
  405. cacheIndex = _.cloneDeep(currentIndex.value);
  406. shipInfoDisabled.value = false;
  407. let { data } = await api.getAddShipCerts({});
  408. let initShipInfo = {
  409. shipId: 0,
  410. disabled: false,
  411. shipCerts: data.result,
  412. };
  413. if (
  414. props.shipInfos.length &&
  415. props.shipInfos[props.shipInfos.length - 1].code
  416. ) {
  417. props.shipInfos.push(initShipInfo);
  418. } else {
  419. props.shipInfos[props.shipInfos.length - 1] = initShipInfo;
  420. }
  421. currentIndex.value = props.shipInfos.length - 1;
  422. }
  423. function cancelAdd() {
  424. currentIndex.value = _.cloneDeep(cacheIndex);
  425. shipInfoDisabled.value = true;
  426. }
  427. let isSubmitLoading = ref(false);
  428. async function submit() {
  429. if (!props.shipInfos[currentIndex.value].shipname) {
  430. ElMessage({
  431. type: "warning",
  432. message: "请填写船舶名称",
  433. });
  434. return;
  435. }
  436. if (!props.shipInfos[currentIndex.value].contentShipOwnerName) {
  437. ElMessage({
  438. type: "warning",
  439. message: "请填写联系人姓名",
  440. });
  441. return;
  442. }
  443. if (!props.shipInfos[currentIndex.value].contentShipOwnerPhone) {
  444. ElMessage({
  445. type: "warning",
  446. message: "请填写联系人手机号",
  447. });
  448. return;
  449. }
  450. isSubmitLoading.value = true;
  451. let res = await api.addShip({
  452. ...props.shipInfos[currentIndex.value],
  453. shipOwnerId: props.shipOwnerId,
  454. });
  455. isSubmitLoading.value = false;
  456. store.commit("removeAlive", "shipOwnerList");
  457. router.replace("/shipOwnerManage/shipOwnerList");
  458. }
  459. let shipInfoDisabled = ref(true);
  460. let cacheInfo = ref({});
  461. function showUpdate() {
  462. cacheInfo.value = _.cloneDeep(props.shipInfos[currentIndex.value]);
  463. shipInfoDisabled.value = false;
  464. }
  465. async function confirmUpdate() {
  466. let postData = props.shipInfos[currentIndex.value];
  467. postData.shipCode = postData.code;
  468. let { data } = await api.updateShip(postData);
  469. if (data.status == 0) {
  470. ElMessage({
  471. message: data.msg,
  472. type: "success",
  473. });
  474. shipInfoDisabled.value = true;
  475. } else {
  476. ElMessage({
  477. message: data.msg,
  478. type: "error",
  479. });
  480. }
  481. }
  482. function cancelUpdate() {
  483. props.shipInfos[currentIndex.value] = _.cloneDeep(cacheInfo.value);
  484. shipInfoDisabled.value = true;
  485. }
  486. function changeDisable(b) {
  487. shipInfoDisabled.value = b;
  488. }
  489. defineExpose({
  490. initCerts,
  491. getShipCerts,
  492. changeDisable,
  493. });
  494. onMounted(() => {});
  495. </script>
  496. <style scoped>
  497. .unit {
  498. width: 40px;
  499. text-align: center;
  500. color: #555;
  501. }
  502. </style>