fix(admin): unify fleet driver trip and operation list layouts

This commit is contained in:
2026-10-07 12:24:21 +08:00
parent ca7f6aa414
commit 04e1d7dbfa
9 changed files with 73 additions and 44 deletions
@@ -31,11 +31,11 @@ const editorOpen = ref(false), editing = ref<DriverDetail | null>(null), actionI
const previewOpen = ref(false), preview = ref<DriverDetail | null>(null)
const fields: QueryField[] = [
{ key: 'keyword', type: 'input', label: '司机关键词', placeholder: '姓名 / 手机 / 司机编号', width: 220 },
{ key: 'region', type: 'select', label: '区域', width: 120, options: [{ label: '国内', value: 'DOMESTIC' }, { label: '海外', value: 'OVERSEAS' }] },
{ key: 'ownership', type: 'select', label: '归属', width: 140, options: [{ label: '自有司机', value: 'OWNED' }, { label: '外派司机', value: 'DISPATCHED' }] },
{ key: 'active', type: 'select', label: '状态', width: 120, options: [{ label: '启用', value: 'true' }, { label: '停用', value: 'false' }] },
{ key: 'reviewStatus', type: 'select', label: '审核状态', width: 140, options: Object.entries(driverReviewLabels).map(([value, label]) => ({ value, label })) },
{ key: 'licenseState', type: 'select', label: '驾照有效期', width: 150, options: Object.entries(driverLicenseLabels).map(([value, label]) => ({ value, label })) },
{ key: 'region', type: 'select', label: '区域', placeholder: '全部区域', width: 120, options: [{ label: '国内', value: 'DOMESTIC' }, { label: '海外', value: 'OVERSEAS' }] },
{ key: 'ownership', type: 'select', label: '归属', placeholder: '全部归属', width: 140, options: [{ label: '自有司机', value: 'OWNED' }, { label: '外派司机', value: 'DISPATCHED' }] },
{ key: 'active', type: 'select', label: '状态', placeholder: '全部状态', width: 120, options: [{ label: '启用', value: 'true' }, { label: '停用', value: 'false' }] },
{ key: 'reviewStatus', type: 'select', label: '审核状态', placeholder: '全部审核状态', width: 140, options: Object.entries(driverReviewLabels).map(([value, label]) => ({ value, label })) },
{ key: 'licenseState', type: 'select', label: '驾照有效期', placeholder: '全部驾照有效期', width: 150, options: Object.entries(driverLicenseLabels).map(([value, label]) => ({ value, label })) },
]
const columns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 205, fixed: 'left', slotName: 'actions' },
@@ -111,15 +111,18 @@ onBeforeUnmount(() => { request++ })
<template>
<AdminPage class="admin-density">
<ListPageLayout>
<div class="driver-summary" aria-label="当前筛选范围司机统计">
<section class="surface-panel"><span>司机总数</span><strong>{{ summary?.total ?? '—' }}</strong><small>自有 {{ summary?.owned ?? '—' }} · 外派 {{ summary?.dispatched ?? '—' }}</small></section>
<button class="surface-panel" type="button" @click="filterExpiry('EXPIRING')"><span>即将到期</span><strong>{{ summary?.expiringSoon ?? '—' }}</strong><small>30 天内到期 · 点击筛选</small></button>
<button class="surface-panel" type="button" @click="filterExpiry('EXPIRED')"><span>驾照已过期</span><strong>{{ summary?.expired ?? '—' }}</strong><small>不可派车 · 点击筛选</small></button>
</div>
<section class="surface-panel"><QueryToolbar v-model="filters" :fields="fields" ariaLabel="司机查询" preference-key="overseas-drivers-query" :loading="loading" @search="search" /></section>
<LoadErrorState v-if="error" title="司机列表加载失败" :message="error.message" @retry="load" ><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :total="total" :loading="loading" row-key="id" empty-text="暂无符合条件的司机">
<ListPageLayout aria-label="司机管理">
<DataTable appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="true" preference-key="overseas-drivers-table" v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :total="total" :loading="loading" row-key="id" empty-text="暂无符合条件的司机">
<template #toolbar-start><h1>司机管理</h1></template>
<template #filters><QueryToolbar v-model="filters" :fields="fields" ariaLabel="司机查询" preference-key="overseas-drivers-query" :loading="loading" @search="search" /></template>
<template #notices>
<LoadErrorState v-if="error" title="司机列表加载失败" :message="error.message" @retry="load"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
<div class="driver-summary" aria-label="当前筛选范围司机统计">
<section class="driver-summary__item"><span>司机总数</span><strong>{{ summary?.total ?? '—' }}</strong><small>自有 {{ summary?.owned ?? '—' }} · 外派 {{ summary?.dispatched ?? '—' }}</small></section>
<button class="driver-summary__item" type="button" @click="filterExpiry('EXPIRING')"><span>即将到期</span><strong>{{ summary?.expiringSoon ?? '—' }}</strong><small>30 天内到期 · 点击筛选</small></button>
<button class="driver-summary__item" type="button" @click="filterExpiry('EXPIRED')"><span>驾照已过期</span><strong>{{ summary?.expired ?? '—' }}</strong><small>不可派车 · 点击筛选</small></button>
</div>
</template>
<template #toolbar-actions><el-button v-if="access.can(permission.driverCreate)" type="primary" @click="create"><Plus :size="16" />新增司机</el-button></template>
<template #actions="{ row }"><RowActions :actions="actions(row as DriverDetail)" text-actions @action="action($event, row as DriverDetail)" /></template>
<template #ownership="{ row }">{{ row.details.ownership === 'OWNED' ? '自有司机' : '外派司机' }}</template>
@@ -140,11 +143,13 @@ onBeforeUnmount(() => { request++ })
</template>
<style scoped>
.driver-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--admin-space-6); }
.driver-summary > * { display: grid; gap: var(--admin-space-3); padding: var(--admin-space-6); text-align: left; color: inherit; font: inherit; }
.driver-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--admin-space-3); }
.driver-summary__item { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--admin-space-2) var(--admin-space-3); padding: var(--admin-space-3); border: 1px solid var(--cc-border); border-radius: var(--admin-radius); background: var(--admin-surface); text-align: left; color: inherit; font: inherit; }
.driver-summary button { cursor: pointer; }
.driver-summary strong { font-size: 24px; }
.driver-summary small { color: var(--cc-muted); }
.driver-summary button:hover { background: var(--el-fill-color-light); }
.driver-summary button:focus-visible { outline: 2px solid var(--el-color-primary); outline-offset: 2px; }
.driver-summary strong { font-size: var(--admin-font-title); font-variant-numeric: tabular-nums; }
.driver-summary small { grid-column: 1 / -1; font-size: var(--admin-font-caption); color: var(--cc-muted); }
.expiry-warning { color: var(--el-color-warning); }
.expiry-danger { color: var(--el-color-danger); }
</style>