49 lines
4.7 KiB
Vue
49 lines
4.7 KiB
Vue
<script setup lang="ts">
|
||
import '@/styles/adminWorkbench.css'
|
||
import '@/styles/adminDensity.css'
|
||
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||
import AdminPage from '@/shared/components/AdminPage.vue'
|
||
import ListPageLayout from '@/shared/components/ListPageLayout.vue'
|
||
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
|
||
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||
import { offerTime } from '../capacityOfferTypes'
|
||
import { listDispatchCapacityDemands, type DispatchCapacityDemand } from '../api/dispatchCapacityDemands'
|
||
const rows = ref<DispatchCapacityDemand[]>([]), page = ref(1), size = ref(20), total = ref(0), loading = ref(false), error = ref<ApiErrorDetails | null>(null)
|
||
const filters = ref<QueryModel>({ origin: '', destination: '' }), applied = ref({ ...filters.value })
|
||
const fields: QueryField[] = [{ key: 'origin', label: '起运仓', type: 'input', placeholder: '起运仓名称', width: 190 }, { key: 'destination', label: '目的地', type: 'input', placeholder: '目的地名称', width: 190 }]
|
||
const amount = (value: number | null | undefined) => value == null ? '—' : String(value)
|
||
const columns: DataTableColumn[] = [
|
||
{ key: 'dispatchNo', label: '排车单号', minWidth: 200 }, { key: 'warehouseName', label: '起运仓', minWidth: 160 },
|
||
{ key: 'route', label: '路线', minWidth: 240, formatter: (row: DispatchCapacityDemand) => row.route || '—' },
|
||
{ key: 'plannedDepartureAt', label: '计划发车', minWidth: 180, formatter: (row: DispatchCapacityDemand) => offerTime(row.plannedDepartureAt) },
|
||
{ key: 'vehiclePalletSpaces', label: '车辆容量(托位)', width: 145, align: 'right', formatter: (row: DispatchCapacityDemand) => amount(row.vehiclePalletSpaces) },
|
||
{ key: 'scheduledPalletCount', label: '已排实托数', width: 120, align: 'right', formatter: (row: DispatchCapacityDemand) => amount(row.scheduledPalletCount) },
|
||
{ key: 'remainingPalletSpaces', label: '剩余标准托位', width: 140, align: 'right', formatter: (row: DispatchCapacityDemand) => row.capacityKnown ? amount(row.remainingPalletSpaces) : '待确认' },
|
||
{ key: 'remainingWeightKg', label: '剩余载重(kg)', width: 145, align: 'right', formatter: (row: DispatchCapacityDemand) => row.capacityKnown ? amount(row.remainingWeightKg) : '待确认' },
|
||
{ key: 'remainingVolumeCbm', label: '剩余容积(m³)', width: 145, align: 'right', formatter: (row: DispatchCapacityDemand) => row.capacityKnown ? amount(row.remainingVolumeCbm) : '待确认' },
|
||
{ key: 'capacityReason', label: '余位状态', minWidth: 220, formatter: (row: DispatchCapacityDemand) => row.capacityKnown ? '余位已确认' : row.capacityReason || '余位待确认' },
|
||
]
|
||
let sequence = 0
|
||
async function load() {
|
||
const current = ++sequence; loading.value = true; error.value = null
|
||
try {
|
||
const value = await listDispatchCapacityDemands({ page: page.value, size: size.value, origin: String(applied.value.origin || '') || undefined, destination: String(applied.value.destination || '') || undefined })
|
||
if (current === sequence) { rows.value = value.records; total.value = value.total }
|
||
} catch (cause) { if (current === sequence) { rows.value = []; total.value = 0; error.value = getApiErrorDetails(cause, '散板需求加载失败') } }
|
||
finally { if (current === sequence) loading.value = false }
|
||
}
|
||
function search() { applied.value = { ...filters.value }; if (page.value === 1) void load(); else page.value = 1 }
|
||
watch([page, size], load); onMounted(load); onBeforeUnmount(() => { sequence++ })
|
||
</script>
|
||
<template><AdminPage class="admin-density admin-workbench"><ListPageLayout aria-label="散板需求"><div class="workbench-table is-page-surface">
|
||
<DataTable appearance="integrated" preference-key="dispatch-capacity-demands" column-settings-mode="show" :results-visible="!error" v-model:page="page" v-model:page-size="size" :columns="columns" :data="rows" :total="total" :loading="loading" row-key="dispatchNo" empty-text="暂无已发布的散板需求">
|
||
<template #toolbar-start><h1>散板需求</h1></template>
|
||
<template #filters><QueryToolbar v-model="filters" :fields="fields" ariaLabel="散板需求查询" :loading="loading" @search="search" /></template>
|
||
<template #notices><LoadErrorState v-if="error" title="散板需求读取失败" :message="error.message" @retry="load"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState></template>
|
||
<template #pagination-left>共 {{ total }} 条散板需求</template>
|
||
</DataTable>
|
||
</div></ListPageLayout></AdminPage></template>
|