优化
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { Download, Plus } from '@lucide/vue'
|
||||
import AdminPage from '@/shared/components/AdminPage.vue'
|
||||
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
|
||||
import ListPageLayout from '@/shared/components/ListPageLayout.vue'
|
||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||||
import ContractPendingNotice from '../components/ContractPendingNotice.vue'
|
||||
import type { VehicleOwnership, VehicleSummary } from '../types'
|
||||
|
||||
const rows = ref<VehicleSummary[]>([])
|
||||
const page = ref(1)
|
||||
const pageSize = ref(20)
|
||||
const ownership = ref<VehicleOwnership>('OWNED')
|
||||
const ownershipTabs: Array<{ label: string; value: VehicleOwnership }> = [
|
||||
{ label: '自有车辆', value: 'OWNED' },
|
||||
{ label: '外派车辆', value: 'DISPATCHED' },
|
||||
]
|
||||
const filters = ref<QueryModel>({ keyword: '', region: '', status: '' })
|
||||
const fields: QueryField[] = [
|
||||
{ key: 'keyword', type: 'input', label: '车辆关键词', placeholder: '车牌 / 司机 / 车型', width: 220 },
|
||||
{ key: 'region', type: 'select', label: '区域', placeholder: '全部区域', width: 140, options: [
|
||||
{ label: '国内', value: 'DOMESTIC' },
|
||||
{ label: '海外', value: 'OVERSEAS' },
|
||||
] },
|
||||
{ key: 'status', type: 'select', label: '状态', placeholder: '全部状态', width: 140, options: [
|
||||
['在役', 'IN_SERVICE'], ['外派中', 'DISPATCHED'], ['维修中', 'MAINTENANCE'], ['停用', 'INACTIVE'], ['已归还', 'RETURNED'],
|
||||
].map(([label, value]) => ({ label, value })) },
|
||||
]
|
||||
const ownedColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', width: 160, fixed: 'left', slotName: 'actions' },
|
||||
{ key: 'plateNumber', prop: 'plateNumber', label: '车牌', minWidth: 130 },
|
||||
{ key: 'model', prop: 'model', label: '车型', minWidth: 180 },
|
||||
{ key: 'fuelConsumptionPer100Km', prop: 'fuelConsumptionPer100Km', label: '油耗(L/100km)', minWidth: 130, align: 'right' },
|
||||
{ key: 'mileageKm', prop: 'mileageKm', label: '当前公里码(km)', minWidth: 140, align: 'right' },
|
||||
{ key: 'driverOrDispatchCompany', prop: 'driverOrDispatchCompany', label: '司机', minWidth: 130 },
|
||||
{ key: 'phone', prop: 'phone', label: '联系电话', minWidth: 145 },
|
||||
{ key: 'status', prop: 'status', label: '状态', width: 100 },
|
||||
{ key: 'region', prop: 'region', label: '区域', width: 100 },
|
||||
]
|
||||
const dispatchedColumns: DataTableColumn[] = [
|
||||
...ownedColumns.slice(0, 5),
|
||||
{ key: 'driverOrDispatchCompany', prop: 'driverOrDispatchCompany', label: '外派单位', minWidth: 160 },
|
||||
{ key: 'phone', prop: 'phone', label: '联系电话', minWidth: 145 },
|
||||
{ key: 'currentDeliveryOrderNo', prop: 'currentDeliveryOrderNo', label: '当前派送单', minWidth: 160 },
|
||||
{ key: 'latestReplacementReason', prop: 'latestReplacementReason', label: '最近更换原因', minWidth: 180 },
|
||||
{ key: 'status', prop: 'status', label: '状态', width: 100 },
|
||||
{ key: 'region', prop: 'region', label: '区域', width: 100 },
|
||||
]
|
||||
const columns = computed(() => ownership.value === 'OWNED' ? ownedColumns : dispatchedColumns)
|
||||
const regionLabel = computed(() => ({ DOMESTIC: '国内', OVERSEAS: '海外' }[String(filters.value.region)] ?? '全部区域'))
|
||||
|
||||
function selectOwnership(value: VehicleOwnership) {
|
||||
if (ownership.value === value) return
|
||||
ownership.value = value
|
||||
page.value = 1
|
||||
}
|
||||
|
||||
function handleOwnershipTabKeydown(event: KeyboardEvent, index: number) {
|
||||
let nextIndex = index
|
||||
if (event.key === 'ArrowRight') nextIndex = (index + 1) % ownershipTabs.length
|
||||
else if (event.key === 'ArrowLeft') nextIndex = (index - 1 + ownershipTabs.length) % ownershipTabs.length
|
||||
else if (event.key === 'Home') nextIndex = 0
|
||||
else if (event.key === 'End') nextIndex = ownershipTabs.length - 1
|
||||
else return
|
||||
event.preventDefault()
|
||||
const tab = ownershipTabs[nextIndex]
|
||||
if (!tab) return
|
||||
selectOwnership(tab.value)
|
||||
const buttons = (event.currentTarget as HTMLElement).parentElement?.querySelectorAll<HTMLElement>('[role="tab"]')
|
||||
buttons?.[nextIndex]?.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AdminPage>
|
||||
<ListPageLayout aria-label="车辆列表">
|
||||
<template #toolbar>
|
||||
<div class="vehicles-query-panel">
|
||||
<div class="status-tabs" role="tablist" aria-label="车辆归属">
|
||||
<button
|
||||
v-for="(tab, index) in ownershipTabs"
|
||||
:key="tab.value"
|
||||
type="button"
|
||||
role="tab"
|
||||
:aria-selected="ownership === tab.value"
|
||||
aria-controls="vehicle-results"
|
||||
:tabindex="ownership === tab.value ? 0 : -1"
|
||||
:class="['status-tab', { 'is-active': ownership === tab.value }]"
|
||||
@click="selectOwnership(tab.value)"
|
||||
@keydown="handleOwnershipTabKeydown($event, index)"
|
||||
>{{ tab.label }}</button>
|
||||
</div>
|
||||
<QueryToolbar v-model="filters" class="vehicles-query-toolbar" :fields="fields" aria-label="车辆筛选" ariaLabel="车辆筛选" preference-key="overseas-vehicles-query" @search="page = 1" />
|
||||
</div>
|
||||
</template>
|
||||
<template #state><ContractPendingNotice domain="车辆管理" /></template>
|
||||
<section id="vehicle-results" class="surface-panel vehicle-panel">
|
||||
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :total="0" preference-key="overseas-vehicles-table" row-key="id" empty-text="车辆查询契约待接入">
|
||||
<template #toolbar-actions>
|
||||
<el-tooltip content="海外区域写接口待接入"><span><el-button type="primary" disabled><Plus :size="16" />添加车辆</el-button></span></el-tooltip>
|
||||
<el-tooltip content="海外区域导出接口待接入"><span><el-button disabled><Download :size="16" />导出Excel</el-button></span></el-tooltip>
|
||||
</template>
|
||||
<template #actions><span class="muted-value">—</span></template>
|
||||
<template #pagination-left>共 0 条{{ regionLabel }}{{ ownership === 'OWNED' ? '自有' : '外派' }}车辆</template>
|
||||
</DataTable>
|
||||
</section>
|
||||
</ListPageLayout>
|
||||
</AdminPage>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.vehicle-panel { min-width: 0; overflow: hidden; }
|
||||
.vehicles-query-panel { overflow: hidden; border: 1px solid var(--cc-border); border-radius: 8px; background: #fff; }
|
||||
.status-tabs { display: flex; max-width: 100%; overflow-x: auto; margin-bottom: 0; border-bottom: 1px solid #e5e7eb; background: #f9fafb; scrollbar-width: thin; }
|
||||
.status-tab { position: relative; flex: 0 0 auto; min-height: 44px; padding: 0 18px; border: 0; background: transparent; color: var(--cc-muted); font: inherit; font-size: 14px; cursor: pointer; }
|
||||
.status-tab::after { position: absolute; right: 12px; bottom: 0; left: 12px; height: 3px; background: transparent; content: ''; }
|
||||
.status-tab:hover { color: var(--cc-primary); background: #f6f9fd; }
|
||||
.status-tab:focus-visible { outline: 2px solid var(--cc-primary); outline-offset: -2px; }
|
||||
.status-tab.is-active { color: var(--cc-primary); font-weight: 600; }
|
||||
.status-tab.is-active::after { background: var(--cc-primary); }
|
||||
.vehicles-query-toolbar { border: 0; }
|
||||
.muted-value { color: var(--cc-muted); }
|
||||
@media (max-width: 720px) { .status-tab { min-height: 46px; padding: 0 14px; } }
|
||||
</style>
|
||||
Reference in New Issue
Block a user