Browse Source

Merge branch 'master' of http://120.26.64.82:10880/BFFE/SZYGM1.0

zhaoke 2 years ago
parent
commit
c077b14569

+ 64 - 10
src/components/SimpleTable/index.vue

@@ -22,7 +22,13 @@
     @selection-change="(...args:any[]) => { emit('selectionChange', ...args) }"
     @sort-change="(...args:any[]) => { emit('sortChange', ...args) }"
   >
-    <el-table-column v-if="sequence" type="index" :width="50" align="center">
+    <el-table-column
+      v-if="sequence"
+      :fixed="hasFixedColumn"
+      type="index"
+      :width="50"
+      align="center"
+    >
       <template #header>
         <TableHeaderCell label="序号" />
       </template>
@@ -36,7 +42,7 @@
         <TableHeaderCell
           v-model:filter-values="filterValueMap[column.columnName]"
           v-model:sort-rule="sortRuleMap[column.columnName]"
-          :label="column.columnLabel"
+          :label="labelFormatter(column.columnLabel)"
           :desc="column.columnDescribe"
           :show-desc="column.showDesc"
           :filter-options="filterOptionMap[column.columnName]"
@@ -53,8 +59,9 @@ import TableHeaderCell from '@/components/TableHeaderCell/index.vue'
 import type { CSSProperties, VNode } from 'vue'
 import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
 import { CommonData, CommonTableColumn } from '~/common'
-import { useTableFilterAndSort } from '@/hooks/useTableFilterAndSort'
+import { Options, useTableFilterAndSort } from '@/hooks/useTableFilterAndSort'
 import { ElTable } from 'element-plus'
+import { useTableSettingsStore } from '@/store/tableSettings'
 
 type SummaryMethod<T> = (data: {
   columns: TableColumnCtx<T>[]
@@ -181,6 +188,9 @@ const props = withDefaults(
     columnProps?: TableColumnProps<CommonData>
     columns: (CommonTableColumn & TableColumnProps<CommonData>)[]
     sequence?: boolean
+    filterSortOptions?: Options
+    cacheKeys?: string[]
+    labelFormatter?: (label: string) => string
   }>(),
   {
     size: 'default',
@@ -190,6 +200,7 @@ const props = withDefaults(
     border: true,
     fit: true,
     showHeader: true,
+    labelFormatter: (label: string) => label,
   }
 )
 
@@ -224,7 +235,17 @@ const tableProps = computed(() => {
   const rawProps = toRaw(props)
   const result: { [x: string]: any } = {}
   Object.entries(rawProps).forEach(([key, value]) => {
-    if (!['columnProps', 'columns'].includes(key) && (value ?? '') !== '') {
+    if (
+      ![
+        'columnProps',
+        'columns',
+        'sequence',
+        'filterSortOptions',
+        'cacheKeys',
+        'labelFormatter',
+      ].includes(key) &&
+      (value ?? '') !== ''
+    ) {
       result[key] = value
     }
     if (props.columns.some(column => column.needCount)) {
@@ -251,20 +272,52 @@ const computedColumnProps = computed(() => {
 const tableColumns = ref<CommonTableColumn[]>([])
 const tableData = ref<CommonData[]>([])
 watchEffect(() => {
-  tableColumns.value = props.columns.map(column => ({
-    label: column.columnLabel,
-    prop: column.columnName,
-    ...column,
-  }))
+  tableColumns.value = props.columns.reduce(
+    (prevColumns: CommonTableColumn[], column) => {
+      if (!column.hidden) {
+        prevColumns.push({
+          label: column.columnLabel,
+          prop: column.columnName,
+          ...column,
+        })
+      }
+      return prevColumns
+    },
+    []
+  )
   tableData.value = props.data
 })
 
+const hasFixedColumn = computed(() =>
+  tableColumns.value.some(column => column.fixed)
+)
+
 const {
   filterOptionMap,
   filterValueMap,
   sortRuleMap,
   dealedTableData,
-} = useTableFilterAndSort(tableColumns, tableData)
+} = useTableFilterAndSort(tableColumns, tableData, props.filterSortOptions)
+
+const { saveTableFilterValues } = useTableSettingsStore()
+
+watch(
+  sortRuleMap,
+  map => {
+    emit('sortRuleChange', map)
+  },
+  { deep: true }
+)
+
+if (props.cacheKeys?.length) {
+  watch(filterValueMap, map => {
+    const values: { [x: string]: string[] } = {}
+    props.cacheKeys!.forEach(columnName => {
+      values[columnName] = map[columnName]
+    })
+    saveTableFilterValues(values)
+  })
+}
 
 const emit = defineEmits([
   'select',
@@ -285,6 +338,7 @@ const emit = defineEmits([
   'currentChange',
   'headerDragend',
   'expandChange',
+  'sortRuleChange',
 ])
 
 const table = ref<InstanceType<typeof ElTable> | null>(null)

+ 8 - 8
src/hooks/useLoop.ts

@@ -9,25 +9,19 @@ export function useLoop(
   let querying = false
   let stopFlag = false
   const startQuery = async () => {
-    if (querying) {
-      return
-    }
-
     querying = true
     stopFlag = false
 
-    await Promise.all(loopFunctions.map(func => func()))
-
+    await Promise.allSettled(loopFunctions.map(func => func()))
     if (stopFlag) {
       return
     }
-
     queryLoop = window.setTimeout(
       startQuery,
       typeof interval === 'string'
         ? LOOP_INTERVAL[interval]
           ? LOOP_INTERVAL[interval]
-          : 5 * 1000
+          : 15 * 1000
         : interval
     )
   }
@@ -46,9 +40,15 @@ export function useLoop(
     })
   }
   onMounted(() => {
+    if (querying) {
+      return
+    }
     startQuery()
   })
   onActivated(() => {
+    if (querying) {
+      return
+    }
     startQuery()
   })
   onDeactivated(() => {

+ 1 - 1
src/hooks/useTableFilterAndSort.ts

@@ -2,7 +2,7 @@ import { Ref } from 'vue'
 import _ from 'lodash'
 import { CommonData, CommonTableColumn, MaybeRef } from '~/common'
 
-interface Options {
+export interface Options {
   defaultFilterValueMap?: { [x: string]: string[] } // 默认筛选条件
   extraFilterValueMap?: MaybeRef<{ [x: string]: string[] }> // 表头之外的额外筛选条件
   defaultSortRuleMap?: { [x: string]: string } // 默认排序条件

+ 24 - 9
src/views/dataQuery/components/DataQueryView/index.vue

@@ -7,6 +7,7 @@
         :model="formData"
         class="data-query-form"
         :rules="rules"
+        @submit.native.prevent
       >
         <div v-if="name !== 'waybill'" class="form-left">
           <el-form-item prop="startDate">
@@ -43,7 +44,7 @@
               placeholder="请输入要搜索的内容"
               :prefix-icon="Search"
               clearable
-              @keyup.enter="dataQuery"
+              @keyup.enter.prevent="dataQuery"
             />
           </el-form-item>
         </div>
@@ -98,8 +99,8 @@ const props = defineProps({
 
 const today = parseTime(new Date(), '{y}-{m}-{d}') as string
 const formData = reactive({
-  startDate: today,
-  endDate: today,
+  startDate: props.name === 'waybill' ? null : today,
+  endDate: props.name === 'waybill' ? null : today,
   keyWords: '',
 })
 watchEffect(() => {
@@ -134,10 +135,15 @@ const keyWordsValidator = (rule: any, value: any, callback: any) => {
   }
   const searchTitle = searchTitleMap[props.name] ?? '关键词'
   if (!value) {
-    return callback(new Error(`请输入${searchTitle}`))
+    if (['flight'].includes(props.name)) {
+      return callback()
+    } else {
+      return callback(new Error(`请输入${searchTitle}`))
+    }
   }
   const regsMap: { [x: string]: RegExp[] } = {
-    flight: [/^[A-Za-z0-9][A-Za-z][0-9]{3,4}$/, /^[0-9]{3,4}$/],
+    // flight: [/^[A-Za-z0-9][A-Za-z][0-9]{3,4}$/, /^[0-9]{3,4}$/],
+    flight: [/^[A-Za-z0-9]{1,6}$/],
     waybill: [/^[0-9]{3}\-[0-9]{8}/],
     freight: [/^[0-9]{5}$/, /^[0-9]{3}\-[0-9]{8}\-[0-9]{5}$/],
   }
@@ -146,7 +152,7 @@ const keyWordsValidator = (rule: any, value: any, callback: any) => {
   if (notMatched) {
     return callback(new Error(`请输入正确的${searchTitle}`))
   }
-  callback()
+  return callback()
 }
 const rules = {
   startDate: [{ required: true, message: '请选择开始日期', trigger: 'blur' }],
@@ -237,11 +243,19 @@ const cellClickHandler = (row, column, cell, event) => {
     case 'waybill': {
       switch (column.property) {
         case 'stockCode': {
-          if (!row.stockCode || !row.flightDate) {
+          if (
+            !row.stockCode ||
+            !row.flightDate ||
+            !['INT', 'DOM'].includes(row.DIType) ||
+            typeof row.FFID !== 'string' ||
+            !['A', 'D'].includes(row.FFID.at(-1))
+          ) {
             ElMessage.error('运单信息缺失!')
             return
           }
-          const viewName = `Waybill`
+          const viewName = `${row.DIType === 'DOM' ? '' : 'International'}${
+            row.FFID.at(-1) === 'D' ? 'Departure' : 'Arrival'
+          }Waybill`
           router.push({
             path: `/dataQuery/waybillQuery/${viewName}`,
             query: {
@@ -275,9 +289,10 @@ const cellClickHandler = (row, column, cell, event) => {
     display: flex;
   }
   &-form :deep {
+    margin-right: 12px;
     flex: 1;
     display: flex;
-    margin-right: 12px;
+    justify-content: flex-end;
     .form-left {
       flex: 1;
       display: flex;

+ 131 - 0
src/views/realTime/components/AirportView/index copy.scss

@@ -0,0 +1,131 @@
+.airport-view {
+  width: calc(100% + calc(var(--app-main-padding) * 2) - 8px);
+  height: 100%;
+  margin-left: calc(var(--app-main-padding) * -1 + 8px);
+  margin-right: calc(var(--app-main-padding) * -1);
+  .airport-header {
+    padding-right: 32px;
+    display: flex;
+    margin-bottom: 16px;
+    .airport-form {
+      margin-right: 30px;
+    }
+    .airport-count {
+      flex: 1;
+      display: flex;
+      align-items: center;
+      .count-box {
+        flex: 1;
+      }
+    }
+    .airport-settings {
+      display: flex;
+      align-items: center;
+      .common-switch {
+        margin-right: 24px;
+      }
+    }
+  }
+  .airport-table {
+    width: 100%;
+    height: calc(100% - 32px - 16px);
+    :deep(.el-table-v2) {
+      .el-table-v2__header-cell,
+      .el-table-v2__row-cell {
+        padding: 0;
+        &:not(:last-of-type) {
+          border-right: 1px solid #dfe3ea;
+        }
+      }
+      .el-table-v2__header-cell-text,
+      .el-table-v2__cell-text {
+        font-size: 12px;
+        font-family: Helvetica, Microsoft YaHei;
+        font-weight: bold;
+        color: #101116;
+        white-space: pre-line;
+      }
+      .el-table-v2__header {
+        .el-table-v2__header-cell {
+          &.bg-yellow {
+            background-color: #f9f3cb;
+          }
+          &.bg-purple {
+            background-color: #9e99d0;
+          }
+          &.bg-green {
+            background-color: #ace5d3;
+          }
+          &.bg-cyan {
+            background-color: #b7d5e8;
+          }
+        }
+      }
+      .el-table-v2__body {
+        .el-table-v2__row {
+          &.bg-gray {
+            background-color: #d2d6df;
+          }
+          &.bg-light {
+            background-color: #eef3d6;
+          }
+          &.underline-red {
+            border-bottom: 2px solid #e83f82;
+          }
+          &.is-selected {
+            background-color: var(--el-table-current-row-bg-color);
+          }
+          .el-table-v2__row-cell {
+            flex-direction: column;
+            &.cell-warning {
+              background-color: #f6cda5;
+            }
+            &.cell-alarm {
+              background-color: #f38080;
+            }
+            &.cell-success {
+              background-color: #46af43;
+            }
+            &.cell-click .el-table-v2__cell-text {
+              color: #2d67e3;
+              cursor: pointer;
+            }
+            .flight-state-cancel {
+              color: #f38080;
+            }
+            .flight-state-delay {
+              color: #d89834;
+            }
+          }
+        }
+        .el-virtual-scrollbar {
+          &.el-vl__horizontal {
+            height: 15px !important;
+          }
+          &.el-vl__vertical {
+            width: 15px !important;
+          }
+        }
+      }
+      .table-footer {
+        padding-left: 8px;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        background-color: #dfe3ea;
+        &-count {
+          font-size: 16px;
+          font-family: Helvetica, Microsoft YaHei;
+          font-weight: bold;
+          color: #303133;
+          &:not(:last-of-type) {
+            margin-right: 48px;
+          }
+        }
+      }
+      .el-empty {
+        height: 100%;
+      }
+    }
+  }
+}

+ 469 - 0
src/views/realTime/components/AirportView/index copy.vue

@@ -0,0 +1,469 @@
+<template>
+  <div class="airport-view">
+    <div class="airport-header">
+      <AirportForm :name="name" @form-data-change="formDataChangeHandler" />
+      <div class="airport-count">
+        <!-- <CountBox
+          :count-number="tableDataCount.waybillCount"
+          :label="isDeparture ? '预计装载总运单数' : '预计卸载总运单数'"
+        />
+        <CountBox
+        v-show="countFlag"
+        :count-number="tableDataCount.goodsCount"
+        :label="isDeparture ? '预计装载总件数' : '预计卸载总件数'"
+        /> -->
+        <CountBox
+          :count-number="tableDataCount.flightCount"
+          label="今日计划航班数"
+        />
+        <CountBox
+          :count-number="
+            isDeparture ? finishedCount : tableDataCount.tallyCount
+          "
+          label="已完成航班数"
+        />
+        <!-- <CountBox
+          :count-number="tableDataCount.weightCount"
+          label="已转载重量"
+        /> -->
+      </div>
+      <div class="airport-settings">
+        <div v-permission="getPermission('count')">
+          <CommonSwitch v-model:flag="countFlag" label="显示件数" />
+        </div>
+        <!-- <div v-permission="getPermission('UTC')">
+          <CommonSwitch v-model:flag="UTCFlag" label="开启UTC" />
+        </div> -->
+        <div v-permission="getPermission('columnSet')">
+          <ColumnSet
+            :table-columns="tableColumns"
+            @checked-submit="columnChecked"
+          />
+        </div>
+      </div>
+    </div>
+    <div class="airport-table">
+      <el-auto-resizer>
+        <template #default="{ height, width }">
+          <el-table-v2
+            ref="tableRef"
+            :style="{ visibility }"
+            :columns="customRendererColumns"
+            :data="dealedTableData"
+            row-key="rowKey"
+            :width="width"
+            :height="height"
+            :fixed="isDeparture"
+            :footer-height="60"
+            :row-class="rowClass"
+            :cell-props="cellPropsGetter"
+            :row-event-handlers="rowEventHandlers"
+            :h-scrollbar-size="15"
+            :v-scrollbar-size="15"
+            scrollbar-always-on
+            @scroll="tableScrollHandler"
+          >
+            <template #footer>
+              <div class="table-footer">
+                <!-- <span class="table-footer-count"
+                  >今日航班总数:{{ tableDataCount.flightCount }}</span
+                > -->
+                <span class="table-footer-count"
+                  >货运航班总数:{{ tableDataCount.freightFlightCount }}</span
+                >
+                <span class="table-footer-count"
+                  >货站交接总数:{{ tableDataCount.depotFlightCount }}</span
+                >
+                <span v-if="isDeparture" class="table-footer-count"
+                  >已装机总数:{{ tableDataCount.loadCount }}</span
+                >
+                <span v-else class="table-footer-count"
+                  >已卸机总数:{{ tableDataCount.unloadCount }}</span
+                >
+                <!-- <span v-if="isDeparture" class="table-footer-count"
+                  >已起飞总数:{{ finishedCount }}</span
+                >
+                <span v-else class="table-footer-count"
+                  >已降落总数:{{ finishedCount }}</span
+                > -->
+              </div>
+            </template>
+          </el-table-v2>
+        </template>
+      </el-auto-resizer>
+    </div>
+  </div>
+</template>
+<script lang="tsx" setup>
+import AirportForm from './AirportForm.vue'
+import ColumnSet from '@/components/ColumnSet/index.vue'
+import CountBox from '../../components/CountBox/index.vue'
+import CommonSwitch from '../../components/CommonSwitch/index.vue'
+import TableHeaderCell from '@/components/TableHeaderCell/index.vue'
+import { useTableColumnSet } from '@/hooks/useTableColumnSet'
+import { useAirportTable } from './useAirportTable'
+import { useTableStyle } from '../../hooks/useTableStyle'
+import { useTableCellClick } from '../../hooks/useTableCellClick'
+import { useTableFilterAndSort } from '@/hooks/useTableFilterAndSort'
+import { useFormatter } from './useFormatter'
+import { ElTableV2, RowEventHandlers, TableV2Instance } from 'element-plus'
+import { CommonData } from '~/common'
+import type {
+  HeaderRenderProps,
+  CellRenderProps,
+  RowClassGetter,
+  ScrollParams,
+} from '../../type'
+import { useLoop } from '@/hooks/useLoop'
+import { useTableSettingsStore } from '@/store/tableSettings'
+import { useFlightState } from './useFlightState'
+
+const props = defineProps({
+  name: {
+    type: String,
+    required: true,
+  },
+})
+
+const isDeparture = props.name.includes('Departure')
+
+const formData: CommonData = reactive({})
+const formDataChangeHandler = (data: CommonData) => {
+  Object.assign(formData, data)
+}
+
+const { tableColumns, tableData, getTableData } = useAirportTable(
+  props.name,
+  formData
+)
+
+const finishedCount = ref(0)
+
+const { warningRules, getWarningRules } = useFlightState(
+  props.name,
+  tableData,
+  finishedCount
+)
+
+useLoop(
+  [
+    // getWarningRules,
+    getTableData,
+  ],
+  'airport',
+  [formData]
+)
+
+const countFlag = ref(false)
+const { tableColumnFormatter, tableDataFormatter } = useFormatter(countFlag)
+
+const UTCFlag = ref(true)
+
+const customRendererColumns = computed(() => [
+  {
+    key: 'rowNO',
+    width: 33,
+    title: '序号',
+    cellRenderer: ({ rowIndex }: CellRenderProps) => (
+      <div class="el-table-v2__cell-text">{rowIndex + 1}</div>
+    ),
+    align: 'center',
+    fixed: isDeparture,
+  },
+  ...tableColumns.value.map(column => ({
+    ...column,
+    headerCellRenderer: ({ column }: HeaderRenderProps) => (
+      <TableHeaderCell
+        v-model:filterValues={filterValueMap[column.columnName]}
+        v-model:sortRule={sortRuleMap[column.columnName]}
+        label={tableColumnFormatter(column.columnLabel)}
+        desc={column.columnDescribe}
+        showDesc={Boolean(column.columnDescribe)}
+        filterOptions={filterOptionMap[column.columnName]}
+        sortable={Boolean(column.needSort)}
+        filterStyle="arrow"
+        onUpdate:sortRule={() => sortChangeHandler(column.columnName)}
+      />
+    ),
+    cellRenderer: (cell: CellRenderProps) => (
+      <>
+        <div
+          class="el-table-v2__cell-text"
+          onClick={() => cellClickHandlerV2(cell)}
+        >
+          {tableDataFormatter(cell)}
+        </div>
+        {
+          cell.column.columnName === 'flightNO' &&
+          (
+            cell.rowData.flightState === 'DLY' && <div class="flight-state-delay">延误</div> ||
+            cell.rowData.flightState === 'CAN' && <div class="flight-state-cancel">取消</div>
+          )
+        }
+      </>
+    ),
+  })),
+])
+
+const { columnChecked } = useTableColumnSet(tableColumns)
+const { rowClassV2, cellClassV2 } = useTableStyle(props.name)
+const cellPropsGetter = params => ({
+  class: cellClassV2(params),
+})
+
+const rowClass: RowClassGetter = params => {
+  const { rowData, rowIndex } = params
+  const classes: string[] = []
+  if (rowData.hasTakenOff === 'Y' || rowData.hasLanded === 'Y') {
+    classes.push('bg-gray')
+    if (
+      ['planDepartureTime', 'planLandingTime'].some(
+        key => sortRuleMap[key] === 'ascending'
+      ) &&
+      finishedCount.value < tableData.value.length &&
+      rowIndex === finishedCount.value - 1
+    ) {
+      classes.push('underline-red')
+    }
+  } else if (rowData.loadPlaneSureTime) {
+    classes.push('bg-light')
+  }
+  if (selectedRowKey.value && rowData.rowKey === selectedRowKey.value) {
+    classes.push('is-selected')
+  }
+
+  return `${rowClassV2(params)} ${classes.join(' ')}`
+}
+const selectedRowKey = ref('')
+watch(formData, () => {
+  selectedRowKey.value = ''
+})
+const rowEventHandlers: RowEventHandlers = {
+  onClick: params => {
+    selectedRowKey.value = params.rowKey as string
+  },
+}
+
+const tableDataCount = computed(() =>
+  tableData.value.reduce(
+    (counts: { [x: string]: number }, current) => {
+      // const preCount = current[isDeparture ? 'preLoad' : 'preUnload']
+      // if (preCount) {
+      //   counts.waybillCount += Number(String(preCount).split('/')[0])
+      //   counts.goodsCount += Number(String(preCount).split('/')[1])
+      // }
+      if (typeof current['allNumber'] === 'number') {
+        counts.flightCount = current['allNumber']
+      }
+      if (current['depotJoinTime'] || current['depotJoinTime_IN']) {
+        counts.depotFlightCount++
+      }
+      const isFreight = tableColumns.value.some(
+        column => column.groupName === '地服相关' && current[column.columnName]
+      )
+      if (isFreight) {
+        counts.freightFlightCount++
+      }
+      if (current['loadPlaneSureTime']) {
+        counts.loadCount++
+      }
+      if (current['unLoadTime']) {
+        counts.unloadCount++
+      }
+      if (current['tallyTime_in']) {
+        counts.tallyCount++
+      }
+      return counts
+    },
+    {
+      // waybillCount: 0,
+      // goodsCount: 0,
+      flightCount: 0,
+      depotFlightCount: 0,
+      freightFlightCount: 0,
+      loadCount: 0,
+      unloadCount: 0,
+      tallyCount: 0,
+      weightCount: 0,
+    }
+  )
+)
+
+const { cellClickHandlerV2 } = useTableCellClick(props.name)
+
+const route = useRoute()
+const {
+  savedTableFilterValueMap,
+  saveTableFilterValues,
+} = useTableSettingsStore()
+const defaultFilterValueMap = savedTableFilterValueMap[route.path]
+const flightStateFilter = computed<{} | { [x: string]: string[] }>(() => {
+  switch (formData.flightState) {
+    case 'hasTakenOff':
+      return { hasTakenOff: ['Y'] }
+    case 'hasNotTakenOff':
+      return { hasTakenOff: ['N'] }
+    case 'hasLanded':
+      return { hasLanded: ['Y'] }
+    case 'hasNotLanded':
+      return { hasLanded: ['N'] }
+    case 'canceled':
+      return { flightState: ['CAN'] }
+    default:
+      return {}
+  }
+})
+
+/* 离港视图默认的排序方式:
+ * 1.已起飞排在前
+ * 2.未起飞中已装机在前
+ * 3.已起飞和未起飞分类中各自按照预计起飞时间排序
+ */
+const defaultSortFunction = (a: CommonData, b: CommonData) => {
+  const departureTimeCompare = (a: CommonData, b: CommonData) => {
+    if (a.planDepartureTime) {
+      if (b.planDepartureTime) {
+        if (a.planDepartureTime > b.planDepartureTime) {
+          return 1
+        } else if (a.planDepartureTime < b.planDepartureTime) {
+          return -1
+        } else {
+          return 0
+        }
+      } else {
+        return -1
+      }
+    } else if (b.planDepartureTime) {
+      return 1
+    } else {
+      return 0
+    }
+  }
+
+  if (a.hasTakenOff === 'Y') {
+    if (b.hasTakenOff === 'Y') {
+      return departureTimeCompare(a, b)
+    } else {
+      return -1
+    }
+  } else if (b.hasTakenOff === 'Y') {
+    return 1
+  } else {
+    if (a.loadPlaneSureTime) {
+      if (b.loadPlaneSureTime) {
+        return departureTimeCompare(a, b)
+      } else {
+        return -1
+      }
+    } else if (b.loadPlaneSureTime) {
+      return 1
+    } else {
+      return departureTimeCompare(a, b)
+    }
+  }
+}
+
+const {
+  filterOptionMap,
+  filterValueMap,
+  sortRuleMap,
+  sortChangeHandler,
+  dealedTableData,
+} = useTableFilterAndSort(tableColumns, tableData, {
+  defaultFilterValueMap,
+  extraFilterValueMap: flightStateFilter,
+  defaultSortRuleMap: isDeparture
+    ? undefined
+    : {
+        planLandingTime: 'ascending',
+      },
+  defaultSortFunction: isDeparture ? defaultSortFunction : undefined,
+})
+const columnsShouldCache = ['IATACode']
+watch(filterValueMap, map => {
+  const values: { [x: string]: string[] } = {}
+  columnsShouldCache.forEach(columnName => {
+    values[columnName] = map[columnName]
+  })
+  saveTableFilterValues(values)
+})
+
+const permissionMap = {
+  DepartureAirport: {
+    count:
+      'number_of_pieces_displayed_in_domestic_departure_terminal_view_button',
+    UTC: 'turn_on_utc_in_view_of_domestic_departure_terminal_button',
+    columnSet: 'domestic_departure_terminal_view_column_setting_button',
+  },
+  InternationalDepartureAirport: {
+    count:
+      'number_of_pieces_displayed_in_international_departure_terminal_view_button',
+    UTC: 'international_departure_terminal_view_opens_utc_button',
+    columnSet: 'international_departure_terminal_view_column_setting_button',
+  },
+  ArrivalAirport: {
+    count:
+      'number_of_pieces_displayed_in_domestic_inbound_terminal_view_button',
+    UTC: 'turn_on_utc_in_view_of_domestic_inbound_terminal_button',
+    columnSet: 'domestic_inbound_terminal_view_column_setting_button',
+  },
+  InternationalArrivalAirport: {
+    count:
+      'number_of_display_pieces_of_international_inbound_terminal_view_button',
+    UTC: 'the_view_of_international_inbound_terminal_opens_utc_button',
+    columnSet: 'view_column_setting_of_international_inbound_terminal_button',
+  },
+}
+const getPermission = (type?: string) => {
+  return [permissionMap[props.name][type]]
+}
+
+const hasSetTableScroll = ref(false)
+watch(
+  [() => formData.startDate, () => formData.endDate],
+  ([startDate, endDate], [preStartDate, preEndDate]) => {
+    if (startDate !== preStartDate || endDate !== preEndDate) {
+      hasSetTableScroll.value = false
+    }
+  }
+)
+watch(tableData, async () => {
+  await nextTick()
+  if (hasSetTableScroll.value || !finishedCount.value) {
+    return
+  }
+  tableRef.value?.scrollToRow(finishedCount.value - 1, 'start')
+  hasSetTableScroll.value = true
+})
+
+// 因为使用了keepalive,需要记录下滚动位置,返回时先滚动到初始位置,再滚动到记录的位置,不然表格会变成空白
+const tableRef = ref<TableV2Instance | null>(null)
+const visibility = ref<'visible' | 'hidden'>('visible')
+const scrollPosition = reactive({
+  x: 0,
+  y: 0,
+})
+const tableScrollHandler = ({ scrollLeft, scrollTop }: ScrollParams) => {
+  scrollPosition.x = scrollLeft
+  scrollPosition.y = scrollTop
+}
+onActivated(() => {
+  const { x, y } = scrollPosition
+  if (x > 0 || y > 0) {
+    visibility.value = 'hidden'
+    tableRef.value?.scrollTo({ scrollLeft: 0, scrollTop: 0 })
+    // 不加延迟的话横向滚动会出错
+    // 等待滚动完成再显示,一定要使用visibility,使用v-show或者说display: none一样会变空白
+    setTimeout(() => {
+      tableRef.value?.scrollTo({
+        scrollLeft: x,
+        scrollTop: y,
+      })
+      visibility.value = 'visible'
+    }, 0)
+  }
+})
+</script>
+<style lang="scss" scoped>
+@import './index.scss';
+</style>

+ 37 - 53
src/views/realTime/components/AirportView/index.scss

@@ -28,25 +28,18 @@
   }
   .airport-table {
     width: 100%;
+    // height: calc(100% - 32px - 16px - 60px);
     height: calc(100% - 32px - 16px);
-    :deep(.el-table-v2) {
-      .el-table-v2__header-cell,
-      .el-table-v2__row-cell {
-        padding: 0;
-        &:not(:last-of-type) {
-          border-right: 1px solid #dfe3ea;
+    :deep(.el-table) {
+      .el-table__cell {
+        .cell,
+        &::after {
+          font-size: 12px;
+          font-weight: bold;
         }
       }
-      .el-table-v2__header-cell-text,
-      .el-table-v2__cell-text {
-        font-size: 12px;
-        font-family: Helvetica, Microsoft YaHei;
-        font-weight: bold;
-        color: #101116;
-        white-space: pre-line;
-      }
-      .el-table-v2__header {
-        .el-table-v2__header-cell {
+      .el-table__header {
+        .el-table__cell {
           &.bg-yellow {
             background-color: #f9f3cb;
           }
@@ -61,21 +54,19 @@
           }
         }
       }
-      .el-table-v2__body {
-        .el-table-v2__row {
-          &.bg-gray {
+      .el-table__body {
+        .el-table__row {
+          &.bg-gray .el-table__cell {
             background-color: #d2d6df;
           }
-          &.bg-light {
+          &.bg-light .el-table__cell {
             background-color: #eef3d6;
           }
           &.underline-red {
             border-bottom: 2px solid #e83f82;
           }
-          &.is-selected {
-            background-color: var(--el-table-current-row-bg-color);
-          }
-          .el-table-v2__row-cell {
+          .el-table__cell {
+            height: 50px;
             flex-direction: column;
             &.cell-warning {
               background-color: #f6cda5;
@@ -86,45 +77,38 @@
             &.cell-success {
               background-color: #46af43;
             }
-            &.cell-click .el-table-v2__cell-text {
+            &.cell-click .el-table__cell-text {
               color: #2d67e3;
               cursor: pointer;
             }
-            .flight-state-cancel {
+            &.flight-state-cancel::after {
+              content: '延误';
+              display: block;
               color: #f38080;
             }
-            .flight-state-delay {
+            &.flight-state-delay::after {
+              content: '取消';
+              display: block;
               color: #d89834;
             }
           }
         }
-        .el-virtual-scrollbar {
-          &.el-vl__horizontal {
-            height: 15px !important;
-          }
-          &.el-vl__vertical {
-            width: 15px !important;
-          }
-        }
       }
-      .table-footer {
-        padding-left: 8px;
-        height: 100%;
-        display: flex;
-        align-items: center;
-        background-color: #dfe3ea;
-        &-count {
-          font-size: 16px;
-          font-family: Helvetica, Microsoft YaHei;
-          font-weight: bold;
-          color: #303133;
-          &:not(:last-of-type) {
-            margin-right: 48px;
-          }
-        }
-      }
-      .el-empty {
-        height: 100%;
+    }
+  }
+  .table-footer {
+    height: 60px;
+    padding-left: 8px;
+    display: flex;
+    align-items: center;
+    background-color: #dfe3ea;
+    &-count {
+      font-size: 16px;
+      font-family: Helvetica, Microsoft YaHei;
+      font-weight: bold;
+      color: #303133;
+      &:not(:last-of-type) {
+        margin-right: 48px;
       }
     }
   }

+ 119 - 255
src/views/realTime/components/AirportView/index.vue

@@ -3,15 +3,6 @@
     <div class="airport-header">
       <AirportForm :name="name" @form-data-change="formDataChangeHandler" />
       <div class="airport-count">
-        <!-- <CountBox
-          :count-number="tableDataCount.waybillCount"
-          :label="isDeparture ? '预计装载总运单数' : '预计卸载总运单数'"
-        />
-        <CountBox
-        v-show="countFlag"
-        :count-number="tableDataCount.goodsCount"
-        :label="isDeparture ? '预计装载总件数' : '预计卸载总件数'"
-        /> -->
         <CountBox
           :count-number="tableDataCount.flightCount"
           label="今日计划航班数"
@@ -43,55 +34,39 @@
       </div>
     </div>
     <div class="airport-table">
-      <el-auto-resizer>
-        <template #default="{ height, width }">
-          <el-table-v2
-            ref="tableRef"
-            :style="{ visibility }"
-            :columns="customRendererColumns"
-            :data="dealedTableData"
-            row-key="rowKey"
-            :width="width"
-            :height="height"
-            :fixed="isDeparture"
-            :footer-height="60"
-            :row-class="rowClass"
-            :cell-props="cellPropsGetter"
-            :row-event-handlers="rowEventHandlers"
-            :h-scrollbar-size="15"
-            :v-scrollbar-size="15"
-            scrollbar-always-on
-            @scroll="tableScrollHandler"
-          >
-            <template #footer>
-              <div class="table-footer">
-                <!-- <span class="table-footer-count"
-                  >今日航班总数:{{ tableDataCount.flightCount }}</span
-                > -->
-                <span class="table-footer-count"
-                  >货运航班总数:{{ tableDataCount.freightFlightCount }}</span
-                >
-                <span class="table-footer-count"
-                  >货站交接总数:{{ tableDataCount.depotFlightCount }}</span
-                >
-                <span v-if="isDeparture" class="table-footer-count"
-                  >已装机总数:{{ tableDataCount.loadCount }}</span
-                >
-                <span v-else class="table-footer-count"
-                  >已卸机总数:{{ tableDataCount.unloadCount }}</span
-                >
-                <!-- <span v-if="isDeparture" class="table-footer-count"
-                  >已起飞总数:{{ finishedCount }}</span
-                >
-                <span v-else class="table-footer-count"
-                  >已降落总数:{{ finishedCount }}</span
-                > -->
-              </div>
-            </template>
-          </el-table-v2>
-        </template>
-      </el-auto-resizer>
+      <SimpleTable
+        ref="tableRef"
+        :columns="tableColumns"
+        :data="tableData"
+        sequence
+        highlight-current-row
+        scrollbar-always-on
+        :stripe="false"
+        show-summary
+        :cache-keys="cacheKeys"
+        :filter-sort-options="filterSortOptions"
+        :label-formatter="tableColumnFormatter"
+        :row-class-name="rowClassName"
+        :cell-class-name="cellClass"
+        :column-props="{ formatter: tableDataFormatter }"
+        @sort-rule-change="sortRuleChangeHandler"
+        @cell-click="cellClickHandler"
+      />
     </div>
+    <!-- <div class="table-footer">
+      <span class="table-footer-count"
+        >货运航班总数:{{ tableDataCount.freightFlightCount }}</span
+      >
+      <span class="table-footer-count"
+        >货站交接总数:{{ tableDataCount.depotFlightCount }}</span
+      >
+      <span v-if="isDeparture" class="table-footer-count"
+        >已装机总数:{{ tableDataCount.loadCount }}</span
+      >
+      <span v-else class="table-footer-count"
+        >已卸机总数:{{ tableDataCount.unloadCount }}</span
+      >
+    </div> -->
   </div>
 </template>
 <script lang="tsx" setup>
@@ -99,21 +74,13 @@ import AirportForm from './AirportForm.vue'
 import ColumnSet from '@/components/ColumnSet/index.vue'
 import CountBox from '../../components/CountBox/index.vue'
 import CommonSwitch from '../../components/CommonSwitch/index.vue'
-import TableHeaderCell from '@/components/TableHeaderCell/index.vue'
+import SimpleTable from '@/components/SimpleTable/index.vue'
 import { useTableColumnSet } from '@/hooks/useTableColumnSet'
 import { useAirportTable } from './useAirportTable'
 import { useTableStyle } from '../../hooks/useTableStyle'
 import { useTableCellClick } from '../../hooks/useTableCellClick'
-import { useTableFilterAndSort } from '@/hooks/useTableFilterAndSort'
 import { useFormatter } from './useFormatter'
-import { ElTableV2, RowEventHandlers, TableV2Instance } from 'element-plus'
 import { CommonData } from '~/common'
-import type {
-  HeaderRenderProps,
-  CellRenderProps,
-  RowClassGetter,
-  ScrollParams,
-} from '../../type'
 import { useLoop } from '@/hooks/useLoop'
 import { useTableSettingsStore } from '@/store/tableSettings'
 import { useFlightState } from './useFlightState'
@@ -139,11 +106,7 @@ const { tableColumns, tableData, getTableData } = useAirportTable(
 
 const finishedCount = ref(0)
 
-const { warningRules, getWarningRules } = useFlightState(
-  props.name,
-  tableData,
-  finishedCount
-)
+const { getWarningRules } = useFlightState(props.name, tableData, finishedCount)
 
 useLoop(
   [
@@ -157,91 +120,92 @@ useLoop(
 const countFlag = ref(false)
 const { tableColumnFormatter, tableDataFormatter } = useFormatter(countFlag)
 
-const UTCFlag = ref(true)
+// const UTCFlag = ref(true)
 
-const customRendererColumns = computed(() => [
-  {
-    key: 'rowNO',
-    width: 33,
-    title: '序号',
-    cellRenderer: ({ rowIndex }: CellRenderProps) => (
-      <div class="el-table-v2__cell-text">{rowIndex + 1}</div>
-    ),
-    align: 'center',
-    fixed: isDeparture,
-  },
-  ...tableColumns.value.map(column => ({
-    ...column,
-    headerCellRenderer: ({ column }: HeaderRenderProps) => (
-      <TableHeaderCell
-        v-model:filterValues={filterValueMap[column.columnName]}
-        v-model:sortRule={sortRuleMap[column.columnName]}
-        label={tableColumnFormatter(column.columnLabel)}
-        desc={column.columnDescribe}
-        showDesc={Boolean(column.columnDescribe)}
-        filterOptions={filterOptionMap[column.columnName]}
-        sortable={Boolean(column.needSort)}
-        filterStyle="arrow"
-        onUpdate:sortRule={() => sortChangeHandler(column.columnName)}
-      />
-    ),
-    cellRenderer: (cell: CellRenderProps) => (
-      <>
-        <div
-          class="el-table-v2__cell-text"
-          onClick={() => cellClickHandlerV2(cell)}
-        >
-          {tableDataFormatter(cell)}
-        </div>
-        {
-          cell.column.columnName === 'flightNO' &&
-          (
-            cell.rowData.flightState === 'DLY' && <div class="flight-state-delay">延误</div> ||
-            cell.rowData.flightState === 'CAN' && <div class="flight-state-cancel">取消</div>
-          )
+/* 离港视图默认的排序方式:
+ * 1.已起飞排在前
+ * 2.未起飞中已装机在前
+ * 3.已起飞和未起飞分类中各自按照预计起飞时间排序
+ */
+const defaultSortFunction = (a: CommonData, b: CommonData) => {
+  const departureTimeCompare = (a: CommonData, b: CommonData) => {
+    if (a.planDepartureTime) {
+      if (b.planDepartureTime) {
+        if (a.planDepartureTime > b.planDepartureTime) {
+          return 1
+        } else if (a.planDepartureTime < b.planDepartureTime) {
+          return -1
+        } else {
+          return 0
         }
-      </>
-    ),
-  })),
-])
+      } else {
+        return -1
+      }
+    } else if (b.planDepartureTime) {
+      return 1
+    } else {
+      return 0
+    }
+  }
+
+  if (a.hasTakenOff === 'Y') {
+    if (b.hasTakenOff === 'Y') {
+      return departureTimeCompare(a, b)
+    } else {
+      return -1
+    }
+  } else if (b.hasTakenOff === 'Y') {
+    return 1
+  } else {
+    if (a.loadPlaneSureTime) {
+      if (b.loadPlaneSureTime) {
+        return departureTimeCompare(a, b)
+      } else {
+        return -1
+      }
+    } else if (b.loadPlaneSureTime) {
+      return 1
+    } else {
+      return departureTimeCompare(a, b)
+    }
+  }
+}
+
+const filterSortOptions = computed(() => ({
+  defaultFilterValueMap,
+  extraFilterValueMap: flightStateFilter,
+  defaultSortRuleMap: isDeparture
+    ? undefined
+    : {
+        planLandingTime: 'ascending',
+      },
+  defaultSortFunction: isDeparture ? defaultSortFunction : undefined,
+}))
+
+const sortRuleMap = ref({})
+const sortRuleChangeHandler = map => {
+  sortRuleMap.value = map
+}
 
 const { columnChecked } = useTableColumnSet(tableColumns)
-const { rowClassV2, cellClassV2 } = useTableStyle(props.name)
-const cellPropsGetter = params => ({
-  class: cellClassV2(params),
-})
+const { rowClass, cellClass } = useTableStyle(props.name)
 
-const rowClass: RowClassGetter = params => {
-  const { rowData, rowIndex } = params
+const rowClassName = params => {
+  const { row, rowIndex } = params
   const classes: string[] = []
-  if (rowData.hasTakenOff === 'Y' || rowData.hasLanded === 'Y') {
-    classes.push('bg-gray')
-    if (
-      ['planDepartureTime', 'planLandingTime'].some(
-        key => sortRuleMap[key] === 'ascending'
-      ) &&
-      finishedCount.value < tableData.value.length &&
-      rowIndex === finishedCount.value - 1
-    ) {
-      classes.push('underline-red')
-    }
-  } else if (rowData.loadPlaneSureTime) {
-    classes.push('bg-light')
-  }
-  if (selectedRowKey.value && rowData.rowKey === selectedRowKey.value) {
-    classes.push('is-selected')
+  if (
+    (row.hasTakenOff === 'Y' || row.hasLanded === 'Y') &&
+    (['planDepartureTime', 'planLandingTime'].some(
+      key => sortRuleMap.value[key] === 'ascending'
+    ) ||
+      Object.keys(sortRuleMap.value).length === 0) &&
+    finishedCount.value < tableData.value.length &&
+    rowIndex === finishedCount.value - 1
+  ) {
+    classes.push('underline-red')
   }
 
-  return `${rowClassV2(params)} ${classes.join(' ')}`
-}
-const selectedRowKey = ref('')
-watch(formData, () => {
-  selectedRowKey.value = ''
-})
-const rowEventHandlers: RowEventHandlers = {
-  onClick: params => {
-    selectedRowKey.value = params.rowKey as string
-  },
+  return `${rowClass(params)} ${classes.join(' ')}`
 }
 
 const tableDataCount = computed(() =>
@@ -289,13 +253,10 @@ const tableDataCount = computed(() =>
   )
 )
 
-const { cellClickHandlerV2 } = useTableCellClick(props.name)
+const { cellClickHandler } = useTableCellClick(props.name)
 
 const route = useRoute()
-const {
-  savedTableFilterValueMap,
-  saveTableFilterValues,
-} = useTableSettingsStore()
+const { savedTableFilterValueMap } = useTableSettingsStore()
 const defaultFilterValueMap = savedTableFilterValueMap[route.path]
 const flightStateFilter = computed<{} | { [x: string]: string[] }>(() => {
   switch (formData.flightState) {
@@ -314,79 +275,7 @@ const flightStateFilter = computed<{} | { [x: string]: string[] }>(() => {
   }
 })
 
-/* 离港视图默认的排序方式:
- * 1.已起飞排在前
- * 2.未起飞中已装机在前
- * 3.已起飞和未起飞分类中各自按照预计起飞时间排序
- */
-const defaultSortFunction = (a: CommonData, b: CommonData) => {
-  const departureTimeCompare = (a: CommonData, b: CommonData) => {
-    if (a.planDepartureTime) {
-      if (b.planDepartureTime) {
-        if (a.planDepartureTime > b.planDepartureTime) {
-          return 1
-        } else if (a.planDepartureTime < b.planDepartureTime) {
-          return -1
-        } else {
-          return 0
-        }
-      } else {
-        return -1
-      }
-    } else if (b.planDepartureTime) {
-      return 1
-    } else {
-      return 0
-    }
-  }
-
-  if (a.hasTakenOff === 'Y') {
-    if (b.hasTakenOff === 'Y') {
-      return departureTimeCompare(a, b)
-    } else {
-      return -1
-    }
-  } else if (b.hasTakenOff === 'Y') {
-    return 1
-  } else {
-    if (a.loadPlaneSureTime) {
-      if (b.loadPlaneSureTime) {
-        return departureTimeCompare(a, b)
-      } else {
-        return -1
-      }
-    } else if (b.loadPlaneSureTime) {
-      return 1
-    } else {
-      return departureTimeCompare(a, b)
-    }
-  }
-}
-
-const {
-  filterOptionMap,
-  filterValueMap,
-  sortRuleMap,
-  sortChangeHandler,
-  dealedTableData,
-} = useTableFilterAndSort(tableColumns, tableData, {
-  defaultFilterValueMap,
-  extraFilterValueMap: flightStateFilter,
-  defaultSortRuleMap: isDeparture
-    ? undefined
-    : {
-        planLandingTime: 'ascending',
-      },
-  defaultSortFunction: isDeparture ? defaultSortFunction : undefined,
-})
-const columnsShouldCache = ['IATACode']
-watch(filterValueMap, map => {
-  const values: { [x: string]: string[] } = {}
-  columnsShouldCache.forEach(columnName => {
-    values[columnName] = map[columnName]
-  })
-  saveTableFilterValues(values)
-})
+const cacheKeys = ['IATACode']
 
 const permissionMap = {
   DepartureAirport: {
@@ -418,6 +307,7 @@ const getPermission = (type?: string) => {
   return [permissionMap[props.name][type]]
 }
 
+const tableRef = ref<InstanceType<typeof SimpleTable> | null>(null)
 const hasSetTableScroll = ref(false)
 watch(
   [() => formData.startDate, () => formData.endDate],
@@ -432,36 +322,10 @@ watch(tableData, async () => {
   if (hasSetTableScroll.value || !finishedCount.value) {
     return
   }
-  tableRef.value?.scrollToRow(finishedCount.value - 1, 'start')
-  hasSetTableScroll.value = true
-})
-
-// 因为使用了keepalive,需要记录下滚动位置,返回时先滚动到初始位置,再滚动到记录的位置,不然表格会变成空白
-const tableRef = ref<TableV2Instance | null>(null)
-const visibility = ref<'visible' | 'hidden'>('visible')
-const scrollPosition = reactive({
-  x: 0,
-  y: 0,
-})
-const tableScrollHandler = ({ scrollLeft, scrollTop }: ScrollParams) => {
-  scrollPosition.x = scrollLeft
-  scrollPosition.y = scrollTop
-}
-onActivated(() => {
-  const { x, y } = scrollPosition
-  if (x > 0 || y > 0) {
-    visibility.value = 'hidden'
-    tableRef.value?.scrollTo({ scrollLeft: 0, scrollTop: 0 })
-    // 不加延迟的话横向滚动会出错
-    // 等待滚动完成再显示,一定要使用visibility,使用v-show或者说display: none一样会变空白
-    setTimeout(() => {
-      tableRef.value?.scrollTo({
-        scrollLeft: x,
-        scrollTop: y,
-      })
-      visibility.value = 'visible'
-    }, 0)
+  if (tableRef.value?.table) {
+    tableRef.value?.table?.setScrollTop((finishedCount.value - 1) * 50)
   }
+  hasSetTableScroll.value = true
 })
 </script>
 <style lang="scss" scoped>

+ 11 - 8
src/views/realTime/components/AirportView/useAirportTable.ts

@@ -1,5 +1,4 @@
 import { Query } from '@/api/webApi'
-import { AnyColumn } from 'element-plus/es/components/table-v2/src/common'
 import { CommonData, CommonTableColumn } from '~/common'
 
 interface SimpleColumn {
@@ -331,7 +330,7 @@ const columnGroupsMap: {
         },
         {
           columnName: 'outWarehouse',
-          columnLabel: '出库\n(批/运单/件)',
+          columnLabel: '出库\n(运单/件/重量)',
         },
         {
           columnName: 'outWarehouseTime',
@@ -703,7 +702,7 @@ const columnGroupsMap: {
         },
         {
           columnName: 'outWarehouse',
-          columnLabel: '出库\n(批/运单/件)',
+          columnLabel: '出库\n(运单/件/重量)',
         },
         {
           columnName: 'outWarehouseTime',
@@ -751,12 +750,12 @@ const computedWidth = (column: SimpleColumn) => {
 }
 
 export function useAirportTable(name: string, formData: CommonData) {
-  const tableColumns = ref<(CommonTableColumn & AnyColumn)[]>([])
+  const tableColumns = ref<CommonTableColumn[]>([])
   const tableData = ref<CommonData[]>([])
   const getTableColumns = () => {
     const groups = columnGroupsMap[name]
     tableColumns.value = groups.reduce(
-      (columns: (CommonTableColumn & AnyColumn)[], group) => {
+      (columns: CommonTableColumn[], group) => {
         group.children.forEach(column => {
           columns.push({
             key: column.columnName,
@@ -765,7 +764,8 @@ export function useAirportTable(name: string, formData: CommonData) {
             columnDescribe: '',
             dataType: '',
             listqueryTemplateID: null,
-            needCount: null,
+            needCount: ['航班相关'].includes(group.groupName) ? 0 : 1,
+            countMode: 'notNull',
             needFilters: null,
             needGroup: null,
             needSearch: null,
@@ -774,10 +774,13 @@ export function useAirportTable(name: string, formData: CommonData) {
             orderNumber: null,
             queryTemplateColumnSetID: null,
             queryTemplateID: null,
-            width: computedWidth(column),
+            width: name.includes('Departure')
+              ? computedWidth(column)
+              : undefined,
             flexGrow: 1,
             align: 'center',
-            headerClass: headerClassMap[group.groupName] ?? '',
+            // headerClass: headerClassMap[group.groupName] ?? '',
+            labelClassName: headerClassMap[group.groupName] ?? '',
             groupName: group.groupName,
             ...column,
           })

+ 16 - 13
src/views/realTime/components/AirportView/useFormatter.ts

@@ -1,4 +1,5 @@
 import { Ref } from 'vue'
+import { CommonTableFormatter } from '~/common'
 import { CellRenderProps } from '../../type'
 
 export function useFormatter(flag: Ref<boolean>) {
@@ -6,34 +7,36 @@ export function useFormatter(flag: Ref<boolean>) {
     return unref(flag) ? columnLabel : columnLabel.replace('/件', '')
   }
 
-  const tableDataFormatter = ({
-    cellData,
-    column: { columnName, columnLabel },
-  }: CellRenderProps) => {
+  const tableDataFormatter: CommonTableFormatter = (
+    row,
+    { label, property },
+    cellValue,
+    index
+  ) => {
     if (!unref(flag)) {
-      const matched = columnLabel.match(/(?<=\()\S+(?=\))/)
+      const matched = label.match(/(?<=\()\S+(?=\))/)
       if (matched) {
         const machedStr = matched[0]
         const countIndex = machedStr.split('/').findIndex(str => str === '件')
         if (
           countIndex > -1 &&
-          typeof cellData === 'string' &&
-          cellData.split('/')[countIndex]
+          typeof cellValue === 'string' &&
+          cellValue.split('/')[countIndex]
         ) {
-          return cellData
+          return cellValue
             .split('/')
             .filter((_, index) => index !== countIndex)
             .join('/')
         }
       }
     }
-    if (columnName.includes('Time') && typeof cellData === 'string') {
-      return cellData.trim().slice(5, -3).replace('T', '\n')
+    if (property.includes('Time') && typeof cellValue === 'string') {
+      return cellValue.trim().slice(5, -3).replace('T', '\n')
     }
-    if (columnName === 'jiahuo') {
-      return cellData ? '是' : '否'
+    if (property === 'jiahuo') {
+      return cellValue ? '是' : '否'
     }
-    return cellData
+    return String(cellValue ?? '')
   }
 
   return {

+ 18 - 18
src/views/realTime/components/FlightView/useFlightInfo.ts

@@ -10,12 +10,12 @@ const flightInfoItemsMap = {
         key: 'departureAirportZh',
       },
       {
-        label: '日期',
-        getter: info => info.planDepartureTime?.split('T')[0],
+        label: '预计起飞时间',
+        getter: info => info.planDepartureTime?.replace('T', ' ') ?? '',
       },
       {
-        label: '时间',
-        getter: info => info.planDepartureTime?.split('T')[1],
+        label: '实际起飞时间',
+        getter: info => info.acDepartureTime?.replace('T', ' ') ?? '',
       },
       {
         label: '停机位',
@@ -45,7 +45,7 @@ const flightInfoItemsMap = {
         key: 'depotJoin',
       },
       {
-        label: '已装载集装器/运单/货物数',
+        label: '已装载集装器/运单数/重量',
         key: 'loadPlane',
       },
       {
@@ -63,12 +63,12 @@ const flightInfoItemsMap = {
         key: 'landingAirportZh',
       },
       {
-        label: '日期',
-        getter: info => info.planLandingTime?.split('T')[0],
+        label: '预计降落时间',
+        getter: info => info.planLandingTime?.replace('T', ' ') ?? '',
       },
       {
-        label: '时间',
-        getter: info => info.planLandingTime?.split('T')[1],
+        label: '实际降落时间',
+        getter: info => info.acLandingTime?.replace('T', ' ') ?? '',
       },
     ],
   ],
@@ -79,12 +79,12 @@ const flightInfoItemsMap = {
         key: 'departureAirportZh',
       },
       {
-        label: '日期',
-        getter: info => info.planDepartureTime?.split('T')[0],
+        label: '预计起飞时间',
+        getter: info => info.planDepartureTime?.replace('T', ' ') ?? '',
       },
       {
-        label: '时间',
-        getter: info => info.planDepartureTime?.split('T')[1],
+        label: '实际起飞时间',
+        getter: info => info.acDepartureTime?.replace('T', ' ') ?? '',
       },
     ],
     [
@@ -106,7 +106,7 @@ const flightInfoItemsMap = {
       //   showOverflowTooltip: true,
       // },
       {
-        label: '卸载数(板/箱/卡)',
+        label: '卸载集装器数(板/箱/卡)',
         key: 'unloadPlaneInfo',
       },
       // {
@@ -120,12 +120,12 @@ const flightInfoItemsMap = {
         key: 'landingAirportZh',
       },
       {
-        label: '日期',
-        getter: info => info.planLandingTime?.split('T')[0],
+        label: '预计降落时间',
+        getter: info => info.planLandingTime?.replace('T', ' ') ?? '',
       },
       {
-        label: '时间',
-        getter: info => info.planLandingTime?.split('T')[1],
+        label: '实际降落时间',
+        getter: info => info.acLandingTime?.replace('T', ' ') ?? '',
       },
       {
         label: '停机位',

+ 2 - 2
src/views/realTime/components/WaybillView/index.vue

@@ -63,13 +63,13 @@
                 <span v-if="index === 0" class="title-span"
                   >航班号:{{ trackAirline.flightNO }}</span
                 >
-                <span
+                <!-- <span
                   v-if="!name.includes('InternationalDeparture')"
                   class="title-span"
                   >{{ trackAirport.isDeparture ? '出港' : '进港' }}:{{
                     trackAirport.airport
                   }}</span
-                >
+                > -->
                 <span class="title-span"
                   >日期:{{ trackAirline.flightDate }}</span
                 >

+ 16 - 0
src/views/realTime/hooks/useTableCellClick.ts

@@ -9,6 +9,22 @@ export function useTableCellClick(tableName?: string) {
   const dialogFlag = ref(false)
 
   const cellClickHandler = (row, column, cell, event) => {
+    if (tableName?.includes('Airport')) {
+      switch (column.property) {
+        case 'flightNO':
+          router.push({
+            path: `${route.path.split('/').slice(0, -1).join('/')}/flight`,
+            query: {
+              flightDate: row.flightDate,
+              flightNO: String(row.IATACode) + String(row.flightNO),
+            },
+          })
+          break
+        default:
+          break
+      }
+    }
+
     if (tableName?.includes('FlightWaybill')) {
       switch (column.property) {
         case 'stockCode':

+ 55 - 0
src/views/realTime/hooks/useTableStyle.ts

@@ -14,6 +14,13 @@ type CellClassGetter = (params: {
 export function useTableStyle(tableName?: string) {
   const rowClass = ({ row, rowIndex }) => {
     const classes: string[] = []
+    if (tableName?.includes('Airport')) {
+      if (row.hasTakenOff === 'Y' || row.hasLanded === 'Y') {
+        classes.push('bg-gray')
+      } else if (row.loadPlaneSureTime) {
+        classes.push('bg-light')
+      }
+    }
     // if (tableName?.includes('FlightContainer')) {
     //   if (rowIndex === 1) {
     //     classes.push('row-warning')
@@ -32,11 +39,56 @@ export function useTableStyle(tableName?: string) {
 
   const cellClass = ({ row, column, rowIndex, columnIndex }) => {
     const classes: string[] = []
+
+    const cellData = row[column.property]
+
+    if (tableName?.includes('Airport')) {
+      if ((['flightNO'] as CommonValue[]).includes(column.property)) {
+        classes.push('cell-click')
+        if (row.flightState === 'DLY') {
+          classes.push('flight-state-delay')
+        } else if (row.flightState === 'CAN') {
+          classes.push('flight-state-cancel')
+        }
+      }
+      if (
+        (column.property === 'register' &&
+          typeof cellData === 'string' &&
+          cellData.split('/').some(char => Number(char) > 0)) ||
+        ((['pullregisterTime', 'pullRegisterTime'] as CommonValue[]).includes(
+          column.property
+        ) &&
+          typeof cellData === 'string')
+      ) {
+        classes.push('cell-warning')
+      }
+      if (
+        tableName?.includes('DepartureAirport') &&
+        (['depotJoin', 'resure'] as any[]).includes(column.property) &&
+        (cellData ?? '') !== ''
+      ) {
+        if (cellData === row['stowage']) {
+          classes.push('cell-success')
+        } else if ((row['planeDownTime'] ?? '') !== '') {
+          classes.push('cell-alarm')
+        }
+      }
+      if (column.property === 'loadPlaneTime') {
+        if (row['warningState'] === 'alarm') {
+          classes.push('cell-alarm')
+        }
+        if (row['warningState'] === 'warning') {
+          classes.push('cell-warning')
+        }
+      }
+    }
+
     if (tableName?.includes('FlightContainer')) {
       if (['stowageNo'].includes(column.property)) {
         classes.push('cell-click')
       }
     }
+
     if (tableName?.includes('FlightWaybill')) {
       if (
         [
@@ -47,16 +99,19 @@ export function useTableStyle(tableName?: string) {
         classes.push('cell-click')
       }
     }
+
     // if (tableName?.includes('WaybillGoods')) {
     //   if (['CargoSN'].includes(column.property)) {
     //     classes.push('cell-click')
     //   }
     // }
+
     if (tableName?.includes('ArrivalWaybillGoods')) {
       if (['C1'].includes(column.property)) {
         classes.push('cell-click')
       }
     }
+
     return classes.join(' ')
   }