ShipInfo.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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 class="df">
  22. <div class="df" v-if="shipInfos[currentIndex].code">
  23. <el-button v-if="shipInfoDisabled" type="primary" @click="showUpdate">
  24. 更新船舶基础信息
  25. </el-button>
  26. <el-button
  27. v-if="!shipInfoDisabled"
  28. type="primary"
  29. @click="confirmUpdate"
  30. >
  31. 确认更新
  32. </el-button>
  33. <el-button
  34. v-if="!shipInfoDisabled"
  35. type="primary"
  36. @click="cancelUpdate"
  37. >
  38. 取消更新
  39. </el-button>
  40. <el-button
  41. v-if="route.name == 'shipOwnerDetail'"
  42. @click="deleteShip(currentIndex)"
  43. type="primary"
  44. class="mr20"
  45. >
  46. 删除当前船舶
  47. </el-button>
  48. </div>
  49. <div class="df" v-if="route.name == 'shipOwnerDetail'">
  50. <el-button
  51. v-if="shipInfos.length == 0 || shipInfos[currentIndex].code"
  52. @click="addShip()"
  53. type="primary"
  54. >
  55. 新增船舶
  56. </el-button>
  57. <div v-else>
  58. <el-button
  59. v-if="shipInfos.length > 1"
  60. @click="cancelAdd()"
  61. type="primary"
  62. >
  63. 取消新增船舶
  64. </el-button>
  65. </div>
  66. </div>
  67. </div>
  68. </div>
  69. <div
  70. v-if="shipInfos[currentIndex].code"
  71. class="df jcfe bgf p20"
  72. style="max-width: 1200px"
  73. ></div>
  74. <div class="line-container-p24">
  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="shipInfos[currentIndex].shipname"
  81. :disabled="shipInfoDisabled"
  82. ></el-input>
  83. <view class="unit"></view>
  84. </div>
  85. <div class="info-line">
  86. <div class="info-line-title">MMSI</div>
  87. <el-input
  88. class="info-line-text"
  89. v-model="shipInfos[currentIndex].mmsi"
  90. :disabled="
  91. shipInfoDisabled ||
  92. !!shipInfos[currentIndex].code ||
  93. !!shipInfos[currentIndex].shipId
  94. "
  95. @blur="searchShip($event, currentIndex)"
  96. ></el-input>
  97. </div>
  98. </div>
  99. <div class="line">
  100. <div class="info-line">
  101. <div class="info-line-title">船长</div>
  102. <el-input
  103. class="info-line-text"
  104. v-model="shipInfos[currentIndex].length"
  105. :disabled="shipInfoDisabled"
  106. ></el-input>
  107. <view class="unit">米</view>
  108. </div>
  109. <div class="info-line">
  110. <div class="info-line-title">船宽</div>
  111. <el-input
  112. class="info-line-text"
  113. v-model="shipInfos[currentIndex].breadth"
  114. :disabled="shipInfoDisabled"
  115. ></el-input>
  116. <view class="unit">米</view>
  117. </div>
  118. </div>
  119. <div class="line">
  120. <div class="info-line">
  121. <div class="info-line-title">吨位</div>
  122. <el-input
  123. class="info-line-text"
  124. v-model="shipInfos[currentIndex].loadTons"
  125. :disabled="shipInfoDisabled"
  126. ></el-input>
  127. <view class="unit">吨</view>
  128. </div>
  129. <div class="info-line">
  130. <div class="info-line-title">船龄</div>
  131. <el-input
  132. class="info-line-text"
  133. v-model="shipInfos[currentIndex].age"
  134. :disabled="shipInfoDisabled"
  135. ></el-input>
  136. <view class="unit">年</view>
  137. </div>
  138. </div>
  139. </div>
  140. <div style="max-width: 1200px">
  141. <div class="container-title">船舶证书</div>
  142. <div
  143. v-for="(item, index) in shipInfos[currentIndex].shipCerts"
  144. :key="item.title"
  145. style="background: #fff"
  146. class="pt20"
  147. >
  148. <div
  149. v-if="index == 4"
  150. class="container-title fs18 pt10 pb10"
  151. style="background: #f3f4f5"
  152. >
  153. 船舶保险
  154. </div>
  155. <div class="df aic pl40 pb20">
  156. <div class="c6 fs16 mr30">{{ item.typeName }}</div>
  157. <div>
  158. <el-date-picker
  159. style="width: 240px"
  160. v-model="item.date"
  161. @change="changeDate($event, index)"
  162. type="daterange"
  163. range-separator="至"
  164. start-placeholder="有效期开始"
  165. end-placeholder="有效期结束"
  166. unlink-panels
  167. value-format="YYYY/MM/DD"
  168. format="YYYY/MM/DD"
  169. />
  170. </div>
  171. </div>
  172. <Uploader
  173. class="pl40 pb20"
  174. :uploaderId="'certsId' + 'country'"
  175. :params="
  176. shipInfos[currentIndex].code
  177. ? {
  178. ...updateParams,
  179. shipCode: shipInfos[currentIndex].code,
  180. type: item.type,
  181. }
  182. : addParams
  183. "
  184. :actionUrl="
  185. shipInfos[currentIndex].code
  186. ? store.state.updateCertsUrl
  187. : store.state.addCertsUrl
  188. "
  189. :disabled="disabled"
  190. :fileList="item.certs"
  191. @onUploadFileList="uploadSuccess($event, index)"
  192. @onRemoveFileList="removeSuccess($event, index)"
  193. ></Uploader>
  194. </div>
  195. <div
  196. v-if="!shipInfos[currentIndex].code"
  197. class="p30 mb30 df jcfe"
  198. style="background: #fff"
  199. >
  200. <el-button @click="submit" type="primary">添加船舶</el-button>
  201. </div>
  202. </div>
  203. </div>
  204. </template>
  205. <script setup>
  206. import { defineComponent, computed, ref, onMounted, watch } from "vue";
  207. import { ElMessage } from "element-plus";
  208. import api from "../apis/fetch";
  209. import _ from "lodash";
  210. import store from "../store";
  211. import { useRoute } from "vue-router";
  212. import router from "../router";
  213. const route = useRoute();
  214. const props = defineProps({
  215. certsId: {
  216. type: String,
  217. default: "cert",
  218. },
  219. disabled: {
  220. type: Boolean,
  221. default: false,
  222. },
  223. shipInfos: {
  224. type: Array,
  225. default: [{}],
  226. },
  227. shipOwnerId: String,
  228. });
  229. let currentIndex = ref(0);
  230. const emit = defineEmits(["submit"]);
  231. function initCerts(certs) {
  232. console.log(certs);
  233. }
  234. let updateParams = ref({
  235. loginAccountId: localStorage.loginAccountId,
  236. });
  237. let addParams = ref({
  238. loginAccountId: localStorage.loginAccountId,
  239. });
  240. // function uploadSuccess(list, index) {
  241. function uploadSuccess({ response, file, list }, index) {
  242. if (response.status == 0) {
  243. let { key, fileKey, viewUrl, downloadUrl, id } = response.result;
  244. props.shipInfos[currentIndex.value].shipCerts[index].certs.push({
  245. fileKey: fileKey || key,
  246. viewUrl,
  247. downloadUrl,
  248. id,
  249. url: viewUrl,
  250. });
  251. }
  252. }
  253. async function removeSuccess({ file, list }, index) {
  254. if (props.shipInfos[currentIndex.value].code) {
  255. let { data } = await api.deleteShipCert({ shipCertId: file.id });
  256. if (data.status == 0) {
  257. ElMessage({
  258. message: "删除成功!",
  259. type: "success",
  260. });
  261. }
  262. } else {
  263. let dataList = [];
  264. for (let i of list) {
  265. dataList.push({
  266. fileKey: i.response.result.key,
  267. downloadUrl: i.response.result.downloadUrl,
  268. viewUrl: i.response.result.viewUrl,
  269. url: i.response.result.viewUrl,
  270. });
  271. }
  272. props.shipInfos[currentIndex.value].shipCerts[index].certs = dataList;
  273. }
  274. }
  275. async function changeDate(e, index) {
  276. if (props.shipInfos[currentIndex.value].code) {
  277. let res = await api.updateShipCertValid({
  278. shipCode: props.shipInfos[currentIndex.value].code,
  279. type: props.shipInfos[currentIndex.value].shipCerts[index].type,
  280. startValidTime: e[0],
  281. endValidTime: e[1],
  282. });
  283. } else {
  284. props.shipInfos[currentIndex.value].shipCerts[index].startValidTime = e[0];
  285. props.shipInfos[currentIndex.value].shipCerts[index].endValidTime = e[1];
  286. }
  287. }
  288. let initShipInfo = {
  289. shipId: 0,
  290. disabled: false,
  291. shipCerts: [
  292. {
  293. typeName: "船舶国籍证书",
  294. type: 1,
  295. date: "",
  296. startValidTime: "",
  297. endtValidTime: "",
  298. certs: [],
  299. },
  300. {
  301. typeName: "内河船舶适航证书",
  302. type: 2,
  303. date: "",
  304. startValidTime: "",
  305. endtValidTime: "",
  306. certs: [],
  307. },
  308. {
  309. typeName: "船舶年审合格证书",
  310. type: 3,
  311. date: "",
  312. startValidTime: "",
  313. endtValidTime: "",
  314. certs: [],
  315. },
  316. {
  317. typeName: "内河船舶最低安全配员证书",
  318. type: 4,
  319. date: "",
  320. startValidTime: "",
  321. endtValidTime: "",
  322. certs: [],
  323. },
  324. {
  325. typeName: "船舶保险",
  326. type: 5,
  327. date: "",
  328. startValidTime: "",
  329. endtValidTime: "",
  330. certs: [],
  331. },
  332. ],
  333. };
  334. function getShipCerts() {
  335. return shipCerts.value;
  336. }
  337. async function searchShip(e) {
  338. if (e.target.value.length != 9) return;
  339. let { data } = await api.searchShip({
  340. mmsi: e.target.value,
  341. });
  342. if (data.status == 0) {
  343. data.result.shipCerts[0].typeName = "船舶国籍证书";
  344. data.result.shipCerts[1].typeName = "内河船舶适航证书";
  345. data.result.shipCerts[2].typeName = "船舶年审合格证书";
  346. data.result.shipCerts[3].typeName = "内河船舶最低安全配员证书";
  347. data.result.shipCerts[4].typeName = "船舶保险";
  348. for (let i of data.result.shipCerts) {
  349. for (let j of i.certs) {
  350. j.url = j.viewUrl;
  351. }
  352. }
  353. data.result.disabled = false;
  354. props.shipInfos[currentIndex.value] = data.result;
  355. }
  356. }
  357. function deleteShip(index) {
  358. ElMessageBox.confirm("确认删除船舶?", "提示", {
  359. confirmButtonText: "确认",
  360. cancelButtonText: "取消",
  361. type: "warning",
  362. })
  363. .then(async () => {
  364. console.log(index);
  365. let { data } = await api.deleteShip({
  366. shipCode: props.shipInfos[index].code,
  367. });
  368. if (data.status == 0) {
  369. ElMessage({
  370. type: "success",
  371. message: "删除成功",
  372. });
  373. props.shipInfos.splice(index, 1);
  374. currentIndex.value = 0;
  375. }
  376. })
  377. .catch(() => {});
  378. }
  379. let cacheIndex = -1;
  380. function addShip(item) {
  381. cacheIndex = _.cloneDeep(currentIndex.value);
  382. shipInfoDisabled.value = false;
  383. if (
  384. props.shipInfos.length &&
  385. props.shipInfos[props.shipInfos.length - 1].code
  386. ) {
  387. props.shipInfos.push(initShipInfo);
  388. } else {
  389. props.shipInfos[props.shipInfos.length - 1] = initShipInfo;
  390. }
  391. currentIndex.value = props.shipInfos.length - 1;
  392. }
  393. function cancelAdd() {
  394. currentIndex.value = _.cloneDeep(cacheIndex);
  395. shipInfoDisabled.value = true;
  396. }
  397. async function submit() {
  398. let res = await api.addShip({
  399. ...props.shipInfos[currentIndex.value],
  400. shipOwnerId: props.shipOwnerId,
  401. });
  402. router.replace("/shipOwnerManage/shipOwnerList");
  403. }
  404. let shipInfoDisabled = ref(true);
  405. let cacheInfo = ref({});
  406. function showUpdate() {
  407. cacheInfo.value = _.cloneDeep(props.shipInfos[currentIndex.value]);
  408. }
  409. async function confirmUpdate() {
  410. let postData = props.shipInfos[currentIndex.value];
  411. postData.shipCode = postData.code;
  412. let { data } = await api.updateShip(postData);
  413. if (data.status == 0) {
  414. ElMessage({
  415. message: data.msg,
  416. type: "success",
  417. });
  418. shipInfoDisabled.value = true;
  419. } else {
  420. ElMessage({
  421. message: data.msg,
  422. type: "error",
  423. });
  424. }
  425. }
  426. function cancelUpdate() {
  427. props.shipInfos[currentIndex.value] = _.cloneDeep(cacheInfo.value);
  428. shipInfoDisabled.value = true;
  429. }
  430. function changeDisable(b) {
  431. shipInfoDisabled.value = b;
  432. }
  433. defineExpose({
  434. initCerts,
  435. getShipCerts,
  436. changeDisable,
  437. });
  438. onMounted(() => {});
  439. </script>
  440. <style scoped>
  441. .unit {
  442. width: 40px;
  443. text-align: center;
  444. color: #555;
  445. }
  446. </style>