baggageView.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. <template>
  2. <div v-loading="loading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)" class="baggageView">
  3. <el-scrollbar style="height: 100%">
  4. <div v-infinite-scroll="" class="baggageView-content">
  5. <div v-for="(item,index) in tableData" :key="index" class="baggageView-list">
  6. <div class="part2">
  7. <div class="part2_info">
  8. <div class="title">
  9. <div class="fightNo">{{ item.carrierFlights || item.inflightNo }}</div>
  10. <div class="fightDate">{{ item.carrierFlightsDate || item.inflightDate }}</div>
  11. <div class="fightLine">{{ item.outAirport }}{{ item.takeoff_terminal }} -- {{item.landAirport}}{{ item.target_terminal }}</div>
  12. <div class="fightTime">{{ item.takeTime }} -- {{ item.landTime }}</div>
  13. </div>
  14. <div class="baggage-track-chart">
  15. <div class="step-line">
  16. <div v-for="(line, index) in 7" :key="index" :class="['step-line-segment', { 'step-line-active': activeStepLine(index,item.bagStatus) }]"></div>
  17. </div>
  18. <div v-for="(p, cindex) in item.bagStatus" :key="cindex" :class="{ 'step-item': true, 'active-item': p.timeValue }">
  19. <div :class="activeStepLineDanger(cindex,item)" class="step-circle">
  20. <span class="step-name">{{ p.nodeName }}</span>
  21. </div>
  22. <div v-if="p.timeValue || p.stateValue || p.loclValue || p.fourSecurity || p.currentResult" class="step-info">
  23. <div :class="statusClasses(p.dataState)">{{ p.dataState }}</div>
  24. <div :class="statusClasses(p.stateValue)">{{ p.stateValue }}</div>
  25. <span class="step-time">{{ p.timeValue }}</span>
  26. <div class="step-location">{{ p.loclValue }}</div>
  27. <div :class="statusClasses(p.fourSecurity)">{{ p.fourSecurity }}</div>
  28. </div>
  29. <div v-else class="step-info">无</div>
  30. </div>
  31. </div>
  32. </div>
  33. </div>
  34. </div>
  35. </div>
  36. </el-scrollbar>
  37. </div>
  38. </template>
  39. <script>
  40. import pf from '@/layout/mixin/publicFunc'
  41. export default {
  42. name: 'BaggageView',
  43. mixins: [pf],
  44. props: {
  45. queryObj: {
  46. type: Object,
  47. default: () => { }
  48. },
  49. tagObj: {
  50. type: Object,
  51. default: () => { }
  52. }
  53. },
  54. data () {
  55. return {
  56. stepNodes: [
  57. {
  58. nodeCode: 'CHECKIN',
  59. nodeName: '值机',
  60. timeProp: 'checkInDate',
  61. timeValue: '',
  62. loclProp: 'checkInLocation',
  63. loclValue: '',
  64. stateProp: 'checkState',
  65. stateValue: '',
  66. },
  67. {
  68. nodeCode: 'B_SECURITY',
  69. nodeName: '开始安检',
  70. timeProp: 'B_security_check_time',
  71. timeValue: '',
  72. loclProp: 'B_security_location',
  73. loclValue: '',
  74. stateProp: 'B_SECURITYState',
  75. stateValue: '',
  76. },
  77. {
  78. nodeCode: 'SECURITY',
  79. nodeName: '安检',
  80. timeProp: 'security_check_time',
  81. timeValue: '',
  82. loclProp: 'security_location',
  83. loclValue: '',
  84. stateProp: 'securityInspectionResults',
  85. stateValue: '',
  86. },
  87. {
  88. nodeCode: 'SORT',
  89. nodeName: '分拣',
  90. timeProp: 'sorting_time',
  91. timeValue: '',
  92. loclProp: 'sorting_location',
  93. loclValue: '',
  94. stateProp: 'sortState',
  95. stateValue: '',
  96. },
  97. {
  98. nodeCode: 'LOAD',
  99. nodeName: '装车',
  100. timeProp: 'loading_time',
  101. timeValue: '',
  102. loclProp: 'installationAddress',
  103. loclValue: '',
  104. stateProp: 'abnormalType',
  105. stateValue: '',
  106. },
  107. {
  108. nodeCode: 'INFL',
  109. nodeName: '装机',
  110. timeProp: 'installation_time',
  111. timeValue: '',
  112. loclProp: 'installation_location',
  113. loclValue: '',
  114. stateProp: 'normal',
  115. stateValue: '',
  116. },
  117. {
  118. nodeCode: 'UNLOAD',
  119. nodeName: '卸机',
  120. timeProp: 'unloadtime',
  121. timeValue: '',
  122. loclProp: 'unloadLocation',
  123. loclValue: '',
  124. stateProp: 'normal',
  125. stateValue: '',
  126. },
  127. {
  128. nodeCode: 'ARRIVED',
  129. nodeName: '到达',
  130. timeProp: 'arrivedtime',
  131. timeValue: '',
  132. loclProp: 'arrviedLocation',
  133. loclValue: '',
  134. stateProp: 'normal',
  135. stateValue: '',
  136. }
  137. ],
  138. tableData: [],
  139. tableDataCopy: [],
  140. page: 0,
  141. pageSize: 20,
  142. dataContent: {},
  143. loading: false,
  144. noMore: false
  145. }
  146. },
  147. computed: {
  148. activeStepLine () {
  149. return function (index, arrs) {
  150. return (arrs[index].stateValue || arrs[index].loclValue || arrs[index].timeValue) && (arrs[index + 1].stateValue || arrs[index + 1].loclValue || arrs[index + 1].timeValue)
  151. }
  152. },
  153. activeStepLineDanger () {
  154. return function (index, item) {
  155. function diffMinutes () {
  156. const { takeTime } = item
  157. const [hour, minutes] = takeTime?.split(':')
  158. if (minutes - 15 >= 0) {
  159. return `${hour}: ${minutes - 15 >= 10 ? minutes - 15 : '0' + (minutes - 15)}`
  160. } else {
  161. if (hour - 1 > 0) {
  162. return `${hour - 1}:${minutes - 15 + 60 >= 10 ? minutes - 15 + 60 : '0' + (minutes - 15 + 60)}`
  163. } else {
  164. return `23:${minutes - 15 + 60 >= 10 ? minutes - 15 + 60 : '0' + (minutes - 15 + 60)}`
  165. }
  166. }
  167. }
  168. const arrs = item.bagStatus
  169. const { stateProp, stateValue,dataState } = arrs[index]
  170. if (stateProp == 'securityInspectionResults' && stateValue == 'UCL') {
  171. if (arrs[index + 1].stateValue || arrs[index + 1].loclValue || arrs[index + 1].timeValue || arrs[index + 2].stateValue || arrs[index + 2].loclValue || arrs[index + 2].timeValue) {
  172. return 'step-circle-waring'
  173. } else {
  174. return 'step-circle-danger'
  175. }
  176. }
  177. if(stateProp == 'checkState'&& dataState =="DEL"){
  178. return 'step-circle-danger'
  179. }
  180. if(stateProp == 'abnormalType'&& stateValue !="" && stateValue !=null){
  181. return 'step-circle-danger'
  182. }
  183. // if (stateProp == 'securityInspectionResults' && !stateValue) {
  184. // if (this.tableData.length >= 2 || arrs[index + 1].stateValue || arrs[index + 1].loclValue || arrs[index + 1].timeValue || arrs[index + 2].stateValue || arrs[index + 2].loclValue || arrs[index + 2].timeValue) {
  185. // return 'step-circle-waring'
  186. // }
  187. // }
  188. }
  189. },
  190. statusClasses () {
  191. return function (status) {
  192. const classes = ['step-status']
  193. if (typeof status === 'string') {
  194. if (status.includes('不正常') || status.includes('不通过') || status.includes('取消') || status.includes('DEL') || status.includes('OFF')|| status.includes('ONA')|| status.includes('OND')|| status.includes('LBA')|| status.includes('UNS')|| status.includes('NAL')) {
  195. classes.push('step-status-abnormal')
  196. }
  197. else if (status.includes('正常') || status.includes('通过')) {
  198. classes.push('step-status-normal')
  199. }
  200. else {
  201. classes.push('step-status-abnormal')
  202. }
  203. }
  204. return classes
  205. }
  206. }
  207. },
  208. watch: {
  209. tagObj: {
  210. handler (obj) {
  211. this.dataContent = _.cloneDeep(obj)
  212. this.restTable()
  213. this.load()
  214. },
  215. deep: true
  216. },
  217. queryObj: {
  218. handler (obj) {
  219. this.tableDataCopy = []
  220. this.tableData = []
  221. this.dataContent = _.cloneDeep(obj)
  222. this.restTable()
  223. this.load()
  224. },
  225. deep: true
  226. },
  227. },
  228. created () {
  229. this.dataContent = _.cloneDeep(this.queryObj)
  230. },
  231. mounted () {
  232. this.restTable()
  233. this.load()
  234. },
  235. methods: {
  236. //获取行李信息
  237. async getLuggageList (id='2203301', dataContent, page, pageSize) {
  238. let parms = {}
  239. parms['carrierFlightsDate'] = this.dataContent.carrierFlightsDate
  240. parms['luggageNum'] = this.dataContent.luggageNum
  241. try {
  242. this.loading = true
  243. const { code, returnData } = await this.getQueryList(id, parms, page, pageSize)
  244. if (code == 0) {
  245. if (returnData.length === 0) {
  246. this.page--;
  247. this.noMore = true;
  248. this.loading = false;
  249. }
  250. returnData.forEach(item => {
  251. item.bagStatus = _.cloneDeep(this.stepNodes)
  252. })
  253. this.tableDataCopy.push(...returnData)
  254. // this.tableDataCopy = _.uniqBy(this.tableDataCopy, 'ID')
  255. // this.tableDataCopy = this.tableDataCopy.sort((a, b) => Date.parse(a.carrierFlightsDate) - Date.parse(b.carrierFlightsDate))
  256. this.tableDataCopy.forEach(item => {
  257. item.bagStatus.map(p => {
  258. const { timeProp, loclProp, stateProp } = p
  259. if (item.hasOwnProperty(timeProp) || item.hasOwnProperty(loclProp) || item.hasOwnProperty(stateProp)) {
  260. p.timeValue = item[timeProp]
  261. p.loclValue = item[loclProp]
  262. p.stateValue = item[stateProp]
  263. }
  264. })
  265. })
  266. this.getBagTime(this.tableDataCopy)
  267. this.loading = false
  268. } else {
  269. this.page--
  270. this.loading = false
  271. this.$message.error("获取表格数据失败")
  272. }
  273. } catch (error) {
  274. this.loading = false;
  275. console.log(error)
  276. }
  277. },
  278. statusSecurity (item) {
  279. const { securityInspectionResults, security_location } = item
  280. const securityNums = ['XSA001', 'XSA003', 'XSB001', 'XSB004']
  281. // if (securityInspectionResults == 'CLR') return securityInspectionResults
  282. // if (securityInspectionResults == 'UCLR') return securityInspectionResults
  283. if (securityNums.includes(security_location)) return 'ULR'
  284. else return securityInspectionResults
  285. },
  286. restTable () {
  287. this.loading = false
  288. this.noMore = false
  289. this.page = 0
  290. this.tableData = []
  291. },
  292. load () {
  293. if (Object.keys(this.queryObj).length || Object.keys(this.tagObj).length) {
  294. if (this.noMore || this.loading) {
  295. return;
  296. }
  297. // this.getPNR()
  298. this.getLuggageList(2203301, this.dataContent, ++this.page, this.pageSize);
  299. }
  300. },
  301. //获取PNR
  302. async getPNR(){
  303. try {
  304. const { carrierFlightsDate,luggageNum } = this.queryObj
  305. const { code, returnData } = await this.getQueryList('21803430', [{
  306. 'carrierFlightsDate': carrierFlightsDate,
  307. 'luggageNum':luggageNum
  308. }]);
  309. if (code == 0) {
  310. if (returnData && returnData.length) {
  311. returnData.map(item => {
  312. this.page = 0
  313. if(item.PNRNO && item.PNRNO!=null){
  314. console.log(item.PNRNO)
  315. let data = {
  316. 'PNRNO':item.PNRNO,
  317. 'carrierFlightsDate':this.dataContent.carrierFlightsDate,
  318. 'luggageNum':item.luggageNum
  319. }
  320. this.getLuggageList(SERVICE_ID.bagTableDqId, data, ++this.page, this.pageSize);
  321. }
  322. else{
  323. this.getLuggageList(SERVICE_ID.bagTableDqId, this.dataContent, ++this.page, this.pageSize);
  324. }
  325. })
  326. }
  327. else{
  328. this.getLuggageList(SERVICE_ID.bagTableDqId, this.dataContent, ++this.page, this.pageSize);
  329. }
  330. } else {
  331. this.$message.error("获取表头数据失败");
  332. }
  333. } catch (error) {
  334. console.log(error)
  335. }
  336. },
  337. async getBagTime (arr) {
  338. const newArr = [...arr]
  339. const reqUrls = []
  340. newArr.forEach(item => {
  341. const { carrierFlights, carrierFlightsDate, outAirport, landAirport, bagStatus } = item
  342. const index = bagStatus.findIndex(citem => citem.stateProp == 'securityInspectionResults')
  343. const index2 = bagStatus.findIndex(citem => citem.stateProp == 'checkState')
  344. const index3 = bagStatus.findIndex(citem => citem.stateProp == 'abnormalType')
  345. if (index > -1) {
  346. bagStatus[index]['stateValue'] = this.statusSecurity(item)
  347. bagStatus[index]['fourSecurity'] = item.fourSecurity
  348. }
  349. if(index2>-1){
  350. bagStatus[index2]['dataState'] = item.dataState
  351. }
  352. if(index3>-1){
  353. bagStatus[index3]['stateValue'] = item.abnormalType
  354. }
  355. const reqItem = this.getQueryList(SERVICE_ID.baggageTime, {
  356. carrierFlights,
  357. carrierFlightsDate,
  358. outAirport,
  359. landAirport
  360. })
  361. reqUrls.push(reqItem)
  362. })
  363. const allReqs = await Promise.allSettled(reqUrls)
  364. allReqs.forEach((item, index) => {
  365. const { status, value } = item
  366. if (status == 'fulfilled') {
  367. const { returnData } = value
  368. const newArray = [...returnData]
  369. if (newArray && newArray.length) {
  370. const itemObj = newArray[0]
  371. const newObj = {}
  372. const { actualTakeOffTime, estimateTakeOffTime, scheduleTakeOffTime, actualLandInTime, estimateLandInTime, scheduleLandInTime } = itemObj
  373. newObj.newTakeoff_time = actualTakeOffTime ? actualTakeOffTime : estimateTakeOffTime ? estimateTakeOffTime : scheduleTakeOffTime
  374. newObj.newLand_time = actualLandInTime ? actualLandInTime : estimateLandInTime ? estimateLandInTime : scheduleLandInTime
  375. newObj.takeTime = newObj.newTakeoff_time?.split('T').at(-1)
  376. newObj.landTime = newObj.newLand_time?.split('T').at(-1)
  377. newArr[index] = Object.assign(newArr[index], newObj)
  378. }
  379. }
  380. })
  381. this.tableData = _.orderBy([...newArr], ["carrierFlightsDate", "takeTime"], ["asc"]);
  382. // this.tableData = this.uniqueJsonArrByField(tableDatas,'carrierFlights')
  383. },
  384. uniqueJsonArrByField (jsonArr, field) {
  385. // 数组长度小于2 或 没有指定去重字段 或 不是json格式数据
  386. if (jsonArr.length < 2 || !field || typeof jsonArr[0] !== "object") return jsonArr;
  387. let uniqueArr = [jsonArr[0]];
  388. for (let i = 1; i < jsonArr.length; i++) {
  389. let item = jsonArr[i];
  390. let filterData = uniqueArr.filter(function (f_item) {
  391. return item[field] && f_item[field] == item[field];
  392. });
  393. if (filterData.length == 0) { // 如果uniqueArr中不存在item
  394. uniqueArr.push(item);
  395. }
  396. }
  397. return uniqueArr;
  398. }
  399. }
  400. }
  401. </script>
  402. <style lang="scss" scoped>
  403. .baggageView {
  404. height: 100%;
  405. &-list {
  406. height: 183px;
  407. border-bottom: 1px solid #dfe3ea;
  408. padding: 30px 32px 47px 32px;
  409. &:last-child {
  410. border-bottom: none;
  411. }
  412. .part2 {
  413. width: 100%;
  414. background: #ffffff;
  415. display: flex;
  416. flex-direction: row;
  417. justify-content: space-between;
  418. align-items: flex-start;
  419. .part2_info {
  420. flex: 1;
  421. display: flex;
  422. flex-direction: row;
  423. justify-content: flex-start;
  424. align-items: flex-start;
  425. line-height: 60px;
  426. .title {
  427. width: 160px;
  428. margin-right: 30px;
  429. font-size: 14px;
  430. font-family: Helvetica;
  431. font-weight: 400;
  432. color: #101116;
  433. line-height: 1;
  434. .fightNo {
  435. font-size: 24px;
  436. font-family: Helvetica;
  437. font-weight: bold;
  438. margin-bottom: 8px;
  439. }
  440. .fightDate {
  441. margin-bottom: 15px;
  442. }
  443. .fightLine {
  444. margin-bottom: 8px;
  445. }
  446. .fightTime {
  447. margin-top: 13px;
  448. }
  449. }
  450. .type {
  451. font-size: 18px;
  452. font-weight: bold;
  453. margin-right: 20px;
  454. .warn {
  455. color: #df3559;
  456. }
  457. .normal {
  458. color: #519f6b;
  459. }
  460. }
  461. .airline {
  462. width: 120px;
  463. margin-right: 20px;
  464. }
  465. .baggage-track-chart {
  466. flex: 1;
  467. height: 124px;
  468. position: relative;
  469. display: flex;
  470. flex-direction: row;
  471. justify-content: space-between;
  472. width: 100%;
  473. }
  474. .step-line {
  475. width: calc(100% - 80px);
  476. height: 10px;
  477. position: absolute;
  478. top: 27px;
  479. right: 0;
  480. left: 0;
  481. margin: auto;
  482. display: flex;
  483. .step-line-segment {
  484. width: calc(100% / 7);
  485. height: 100%;
  486. background: #afb4bf;
  487. &.step-line-active {
  488. background: #2d67e3;
  489. }
  490. }
  491. }
  492. .step-item {
  493. width: 80px;
  494. height: 100%;
  495. text-align: center;
  496. font-size: 14px;
  497. display: flex;
  498. flex-direction: column;
  499. align-items: center;
  500. justify-content: flex-start;
  501. z-index: 1;
  502. font-family: Helvetica, "Microsoft Yahei";
  503. .step-circle {
  504. width: 60px;
  505. height: 60px;
  506. border-radius: 50%;
  507. background: #aaacb2;
  508. .step-name {
  509. color: #ffffff;
  510. font-size: 14px;
  511. font-weight: bold;
  512. }
  513. }
  514. .step-info {
  515. margin-top: 8px;
  516. color: #101116;
  517. line-height: 22px;
  518. .step-status {
  519. &-normal {
  520. color: #4ab36f;
  521. }
  522. &-abnormal {
  523. color: #e9af4b;
  524. }
  525. }
  526. .step-time {
  527. white-space: pre-line;
  528. font-size: 12px;
  529. line-height: 20px;
  530. }
  531. }
  532. &.active-item .step-circle {
  533. background: #2d67e3;
  534. }
  535. .step-circle-danger {
  536. background: #ff3303 !important;
  537. }
  538. .step-circle-waring {
  539. background: #2d67e3;
  540. }
  541. }
  542. }
  543. .btns {
  544. margin-top: 6px;
  545. }
  546. }
  547. }
  548. }
  549. </style>