|
|
@@ -0,0 +1,367 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, onMounted } from 'vue'
|
|
|
+import { type VxeGridInstance, type VxeGridProps } from 'vxe-table'
|
|
|
+import { useRowClickStyle } from '@/hooks/rowClickStyle'
|
|
|
+import { formatNumber } from '@/utils/tools'
|
|
|
+import dayjs from 'dayjs'
|
|
|
+import { autoWidth } from '@/utils/table'
|
|
|
+import { useLoadingState } from '@/stores/modules/loadingState'
|
|
|
+import { useCalculatingHeight } from '@/hooks/calculatingHeight'
|
|
|
+
|
|
|
+const filterRef: Ref<HTMLElement | null> = ref(null)
|
|
|
+
|
|
|
+const containerHeight = useCalculatingHeight(document.documentElement, 446, [filterRef])
|
|
|
+
|
|
|
+const columnstest = ref([
|
|
|
+ {
|
|
|
+ title: 'Reference No. ',
|
|
|
+ field: 'reference_no',
|
|
|
+ displayName: 'Reference No. ',
|
|
|
+ type: 'normal',
|
|
|
+ formatter:'',
|
|
|
+ checked: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Purchase',
|
|
|
+ field: 'purchase',
|
|
|
+ displayName: 'Purchase',
|
|
|
+ type: 'normal',
|
|
|
+ formatter:'',
|
|
|
+ checked: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'House Bill of Lading',
|
|
|
+ field: 'house_bill_of_lading',
|
|
|
+ displayName: '',
|
|
|
+ type: 'normal',
|
|
|
+ formatter:'',
|
|
|
+ checked: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Master Bill of Lading',
|
|
|
+ field: 'master_bill_of_lading',
|
|
|
+ displayName: '',
|
|
|
+ type: 'normal',
|
|
|
+ formatter:'',
|
|
|
+ checked: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Vessel Name',
|
|
|
+ field: 'vessel_name',
|
|
|
+ displayName: '',
|
|
|
+ type: 'normal',
|
|
|
+ formatter:'',
|
|
|
+ checked: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Status',
|
|
|
+ field: 'status',
|
|
|
+ displayName: '',
|
|
|
+ type: 'status',
|
|
|
+ formatter:'',
|
|
|
+ checked: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Container Number',
|
|
|
+ field: 'container_number',
|
|
|
+ displayName: '',
|
|
|
+ type: 'normal',
|
|
|
+ formatter:'',
|
|
|
+ checked: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Service Type',
|
|
|
+ field: 'service_type',
|
|
|
+ displayName: '',
|
|
|
+ type: 'normal',
|
|
|
+ formatter:'',
|
|
|
+ checked: true
|
|
|
+ },
|
|
|
+])
|
|
|
+const ColumnSortValue = ref('')
|
|
|
+const SelectedValue = ref('')
|
|
|
+const ColumnSortoptions = [
|
|
|
+ {
|
|
|
+ value: 'Option1',
|
|
|
+ label: 'Option1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 'Option2',
|
|
|
+ label: 'Option2',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 'Option3',
|
|
|
+ label: 'Option3',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 'Option4',
|
|
|
+ label: 'Option4',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 'Option5',
|
|
|
+ label: 'Option5',
|
|
|
+ },
|
|
|
+]
|
|
|
+const sortOptions = ref([
|
|
|
+ {
|
|
|
+ label: 'Ascending',
|
|
|
+ value: 'Ascending'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: 'Descending',
|
|
|
+ value: 'Descending'
|
|
|
+ }
|
|
|
+])
|
|
|
+
|
|
|
+const loadingState = useLoadingState()
|
|
|
+const tableLoadingColumn = ref(false)
|
|
|
+const tableLoadingTable = ref(false)
|
|
|
+const exportLoading = ref(false)
|
|
|
+
|
|
|
+const tableData = ref<VxeGridProps<any>>({
|
|
|
+ border: true,
|
|
|
+ round: true,
|
|
|
+ columns: [],
|
|
|
+ data: [],
|
|
|
+ scrollY: { enabled: true, oSize: 20, gt: 30 },
|
|
|
+ stripe: true,
|
|
|
+ emptyText: ' ',
|
|
|
+ showHeaderOverflow: true,
|
|
|
+ showOverflow: true,
|
|
|
+ headerRowStyle: {
|
|
|
+ backgroundColor: 'var(--color-table-header-bg)'
|
|
|
+ },
|
|
|
+ columnConfig: { resizable: true, useKey: true },
|
|
|
+ rowConfig: { isHover: true },
|
|
|
+ exportConfig: {
|
|
|
+ types: ['csv', 'html', 'txt', 'xlsx'],
|
|
|
+ modes: ['current', 'selected', 'all']
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const tableRef = ref<VxeGridInstance | null>(null)
|
|
|
+const pageInfo = ref({ pageNo: 1, pageSize: 50, total: 0 })
|
|
|
+
|
|
|
+const handleColumns = (columns: any) => {
|
|
|
+ const newColumns = columns.map((item: any) => {
|
|
|
+ let curColumn: any = {
|
|
|
+ title: item.title,
|
|
|
+ field: item.field,
|
|
|
+ width: item.width
|
|
|
+ }
|
|
|
+ // 设置插槽
|
|
|
+ if (item.type === 'status') {
|
|
|
+ curColumn = {
|
|
|
+ ...curColumn,
|
|
|
+ slots: { default: 'status' }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return curColumn
|
|
|
+ })
|
|
|
+ return newColumns
|
|
|
+}
|
|
|
+const emit = defineEmits(['getManageCoulumns'])
|
|
|
+// 获取表格列
|
|
|
+const getTableColumns = async () => {
|
|
|
+ // tableLoadingColumn.value = true
|
|
|
+ tableData.value.columns = handleColumns(columnstest.value)
|
|
|
+ emit('getManageCoulumns', columnstest.value)
|
|
|
+ nextTick(() => {
|
|
|
+ tableRef.value && autoWidth(tableData.value, tableRef.value)
|
|
|
+ tableLoadingColumn.value = false
|
|
|
+ })
|
|
|
+}
|
|
|
+// 获取表格数据
|
|
|
+const getTableData = (isPageChange?: boolean) => {
|
|
|
+ tableLoadingTable.value = true
|
|
|
+ $api
|
|
|
+ .getConfigurationList({
|
|
|
+ cp: pageInfo.value.pageNo,
|
|
|
+ ps: pageInfo.value.pageSize,
|
|
|
+ rc: isPageChange ? pageInfo.value.total : -1
|
|
|
+ })
|
|
|
+ .then((res: any) => {
|
|
|
+ if (res.code === 200) {
|
|
|
+ pageInfo.value.total = Number(res.data.rc)
|
|
|
+ pageInfo.value.pageNo = res.data.cp
|
|
|
+ pageInfo.value.pageSize = res.data.ps
|
|
|
+ tableData.value.data = [
|
|
|
+ {
|
|
|
+ reference_no: '1234567890',
|
|
|
+ purchase: 'Purchase',
|
|
|
+ house_bill_of_lading: 'House Bill of Lading',
|
|
|
+ master_bill_of_lading: 'Master Bill of Lading',
|
|
|
+ vessel_name: 'Vessel Name',
|
|
|
+ status: 'Created',
|
|
|
+ container_number: 'Container Number',
|
|
|
+ service_type: 'Service Type'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .finally(() => {
|
|
|
+ nextTick(() => {
|
|
|
+ tableRef.value && autoWidth(tableData.value, tableRef.value)
|
|
|
+ tableLoadingTable.value = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 查询时调用接口
|
|
|
+const handleSearch = (val: any) => {
|
|
|
+ tableLoadingTable.value = true
|
|
|
+ setTimeout(() => {
|
|
|
+ tableLoadingTable.value = false
|
|
|
+ }, 1000);
|
|
|
+}
|
|
|
+// 下载
|
|
|
+const getExportTableData = (type: string, column: any) => {
|
|
|
+ if(column) {
|
|
|
+ const newColumns = column.map((item: any) => {
|
|
|
+ let curColumn: any = {
|
|
|
+ title: item.displayName != '' ? item.displayName : item.title,
|
|
|
+ field: item.field,
|
|
|
+ width: item.width
|
|
|
+ }
|
|
|
+ return curColumn
|
|
|
+ })
|
|
|
+ column = newColumns
|
|
|
+ }
|
|
|
+ exportLoading.value = true
|
|
|
+ const exportConfig: any = {
|
|
|
+ type: type,
|
|
|
+ message: false,
|
|
|
+ filename: `Report List_${dayjs().format('YYYYMMDDHH[h]mm[m]ss[s]')}`,
|
|
|
+ columns: column || tableData.value.columns
|
|
|
+ }
|
|
|
+
|
|
|
+ tableRef.value.exportData(exportConfig)
|
|
|
+ setTimeout(() => {
|
|
|
+ exportLoading.value = false
|
|
|
+ }, 1000)
|
|
|
+}
|
|
|
+
|
|
|
+// 实现行点击样式
|
|
|
+useRowClickStyle(tableRef)
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ getTableColumns()
|
|
|
+ getTableData()
|
|
|
+})
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ handleSearch,
|
|
|
+ getExportTableData
|
|
|
+})
|
|
|
+</script>
|
|
|
+<template>
|
|
|
+ <div
|
|
|
+ v-loading.fullscreen.lock="exportLoading"
|
|
|
+ element-loading-text="Loading..."
|
|
|
+ element-loading-custom-class="element-loading"
|
|
|
+ element-loading-background="rgb(43, 47, 54, 0.7)"
|
|
|
+ >
|
|
|
+ <div class="SettingTable">
|
|
|
+ <div class="flex">
|
|
|
+ <div class="Title">
|
|
|
+ Report Data Review
|
|
|
+ </div>
|
|
|
+ <div class="flex">
|
|
|
+ <span class="sort-text">Sort by:</span>
|
|
|
+ <el-select style="width: 160px;margin: 0 8px;" v-model="ColumnSortValue" placeholder="Please select...">
|
|
|
+ <el-option
|
|
|
+ v-for="item in ColumnSortoptions"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-select style="width: 124px;" v-model="SelectedValue" placeholder="Please select...">
|
|
|
+ <el-option
|
|
|
+ v-for="item in sortOptions"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <vxe-grid
|
|
|
+ ref="tableRef"
|
|
|
+ :style="{ border: 'none'}"
|
|
|
+ v-bind="tableData"
|
|
|
+ :height="containerHeight"
|
|
|
+ v-vloading="tableLoadingColumn || tableLoadingTable || loadingState.trackingTableLoading"
|
|
|
+ >
|
|
|
+ <!-- 空数据时的插槽 -->
|
|
|
+ <template #empty>
|
|
|
+ <img src="../images/default_no_data@2x.png" />>
|
|
|
+ <div class="empty-text">No data</div>
|
|
|
+ </template>
|
|
|
+ <!-- Status字段的插槽 -->
|
|
|
+ <template #status="{ row, column }">
|
|
|
+ <VTag :type="row[column.field]">{{ row[column.field] }}</VTag>
|
|
|
+ </template>
|
|
|
+ </vxe-grid>
|
|
|
+ </div>
|
|
|
+ <div class="pagination">
|
|
|
+ <span>Total {{ formatNumber(pageInfo.total) }}</span>
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="pageInfo.pageNo"
|
|
|
+ v-model:page-size="pageInfo.pageSize"
|
|
|
+ :page-sizes="[50, 100, 200, 300, 400]"
|
|
|
+ :pagerCount="5"
|
|
|
+ background
|
|
|
+ layout="sizes, prev, pager, next"
|
|
|
+ :total="pageInfo.total"
|
|
|
+ @size-change="getTableData(true)"
|
|
|
+ @current-change="getTableData(true)"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.flex {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ .sort-text {
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 400;
|
|
|
+ color: var(--color-neutral-2);
|
|
|
+ }
|
|
|
+}
|
|
|
+.Title {
|
|
|
+ font-size: var(--font-size-6);
|
|
|
+ font-weight: 700;
|
|
|
+ margin-bottom: 13px;
|
|
|
+}
|
|
|
+.pagination {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 15px;
|
|
|
+ align-items: center;
|
|
|
+ margin: 0 24px;
|
|
|
+ border: 1px solid var(--color-border);
|
|
|
+ border-top: none;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 0 0 6px 6px;
|
|
|
+}
|
|
|
+:deep(.el-icon svg) {
|
|
|
+ width: 1em !important;
|
|
|
+}
|
|
|
+.SettingTable {
|
|
|
+ padding: 13px 24px 0 24px;
|
|
|
+ font-weight: 400;
|
|
|
+ border-top: 1px solid var(--color-border);
|
|
|
+}
|
|
|
+.empty-text {
|
|
|
+ margin: 8px 0;
|
|
|
+ color: var(--color-neutral-2);
|
|
|
+ text-align: center;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+</style>
|