refine Semi UI vehicle discovery on mobile

This commit is contained in:
lingniu
2026-07-18 08:41:39 +08:00
parent 9a49d015cf
commit 31dd36ee70
3 changed files with 50 additions and 18 deletions

View File

@@ -222,11 +222,16 @@ test('defaults to a compact mobile vehicle directory and keeps eight recent vehi
expect(screen.getAllByRole('listitem', { name: /打开 .* 车辆档案/ })).toHaveLength(8); expect(screen.getAllByRole('listitem', { name: /打开 .* 车辆档案/ })).toHaveLength(8);
expect(view.container.querySelector('.v2-vehicle-directory-table')).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-vehicle-directory-table')).not.toBeInTheDocument();
expect(view.container.querySelector('.v2-vehicle-query-panel')).toHaveClass('is-mobile-collapsed'); expect(view.container.querySelector('.v2-vehicle-query-panel')).toHaveClass('is-mobile-collapsed');
const toggle = screen.getByRole('button', { name: '修改车辆定位10 辆授权车辆' }); expect(screen.queryByLabelText('查车操作')).not.toBeInTheDocument();
const toggle = screen.getByRole('button', { name: '修改车辆筛选10 辆授权车辆' });
expect(toggle).toHaveAttribute('aria-expanded', 'false'); expect(toggle).toHaveAttribute('aria-expanded', 'false');
fireEvent.click(toggle); fireEvent.click(toggle);
expect(view.container.querySelector('.v2-vehicle-query-panel')).not.toHaveClass('is-mobile-collapsed'); expect(view.container.querySelector('.v2-vehicle-query-panel')).not.toHaveClass('is-mobile-collapsed');
expect(screen.getByRole('textbox', { name: '搜索车辆' })).toBeVisible(); const input = screen.getByRole('textbox', { name: '搜索车辆' });
expect(input).toBeVisible();
expect(view.container.querySelector('.v2-vehicle-search-options')).not.toBeInTheDocument();
fireEvent.focus(input);
expect(view.container.querySelector('.v2-vehicle-search-options')).toBeInTheDocument();
}); });
test('paginates the complete desktop authorized vehicle directory', async () => { test('paginates the complete desktop authorized vehicle directory', async () => {

View File

@@ -1,5 +1,5 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { IconArrowRight, IconChevronRight, IconRefresh, IconSearch } from '@douyinfe/semi-icons'; import { IconArrowRight, IconBox, IconChevronRight, IconRefresh, IconSearch } from '@douyinfe/semi-icons';
import { Button, Card, Empty, Input, Table, Tag } from '@douyinfe/semi-ui'; import { Button, Card, Empty, Input, Table, Tag } from '@douyinfe/semi-ui';
import { type FormEvent, lazy, Suspense, useDeferredValue, useEffect, useMemo, useRef, useState } from 'react'; import { type FormEvent, lazy, Suspense, useDeferredValue, useEffect, useMemo, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@@ -61,7 +61,12 @@ export default function VehicleSearchWorkspace() {
const pageVehicles = useMemo(() => options.slice(0, pageSize), [options, pageSize]); const pageVehicles = useMemo(() => options.slice(0, pageSize), [options, pageSize]);
const total = candidates.data?.total ?? 0; const total = candidates.data?.total ?? 0;
const totalPages = Math.max(1, Math.ceil(total / pageSize)); const totalPages = Math.max(1, Math.ceil(total / pageSize));
const administrator = canAdminister(session);
useEffect(() => () => window.clearTimeout(closeTimerRef.current), []); useEffect(() => () => window.clearTimeout(closeTimerRef.current), []);
useEffect(() => {
setFiltersCollapsed(mobileLayout);
setCandidatesOpen(false);
}, [mobileLayout]);
const openCandidates = () => { const openCandidates = () => {
window.clearTimeout(closeTimerRef.current); window.clearTimeout(closeTimerRef.current);
setCandidatesOpen(true); setCandidatesOpen(true);
@@ -86,18 +91,18 @@ export default function VehicleSearchWorkspace() {
}; };
const vehicleScope = candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权` : '授权范围'; const vehicleScope = candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权` : '授权范围';
return <section className={`v2-vehicle-search-page${syncOpen ? ' has-sync-panel' : ''}${candidatesOpen ? ' has-candidates' : ''}`}> return <section className={`v2-vehicle-search-page${syncOpen ? ' has-sync-panel' : ''}${candidatesOpen ? ' has-candidates' : ''}`}>
<WorkspaceCommandBar {!mobileLayout || administrator ? <WorkspaceCommandBar
className="v2-vehicle-command-bar" className={`v2-vehicle-command-bar${mobileLayout ? ' is-mobile-admin' : ''}`}
ariaLabel="查车操作" ariaLabel={mobileLayout ? '车辆主档操作' : '查车操作'}
title="车辆快速定位" title={mobileLayout ? '车辆主档' : '车辆快速定位'}
description="车牌、VIN 或手机号快速查车" description={mobileLayout ? '批量维护品牌、车型与运营属性' : '车牌、VIN 或手机号快速查车'}
status={candidates.isPending ? '正在读取授权范围' : vehicleScope} status={mobileLayout ? undefined : candidates.isPending ? '正在读取授权范围' : vehicleScope}
statusColor={candidates.isError ? 'red' : 'blue'} statusColor={candidates.isError ? 'red' : 'blue'}
actions={canAdminister(session) ? <Button theme="light" onClick={() => setSyncOpen((value) => !value)}>{syncOpen ? '收起主档同步' : '批量同步主档'}</Button> : null} actions={administrator ? <Button theme="light" type="tertiary" icon={mobileLayout ? <IconBox /> : undefined} onClick={() => setSyncOpen((value) => !value)}>{syncOpen ? '收起同步' : mobileLayout ? '主档同步' : '批量同步主档'}</Button> : null}
/> /> : null}
<WorkspaceFilterPanel <WorkspaceFilterPanel
className="v2-vehicle-query-panel" className="v2-vehicle-query-panel"
title="车辆定位" title={mobileLayout ? '车辆筛选' : '车辆定位'}
description="车牌优先VIN 辅助" description="车牌优先VIN 辅助"
mobileSummary={deferredKeyword ? `正在查找 ${deferredKeyword}` : candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权车辆` : '正在读取授权范围'} mobileSummary={deferredKeyword ? `正在查找 ${deferredKeyword}` : candidates.data ? `${candidates.data.total.toLocaleString('zh-CN')} 辆授权车辆` : '正在读取授权范围'}
expanded={!filtersCollapsed} expanded={!filtersCollapsed}
@@ -141,7 +146,7 @@ export default function VehicleSearchWorkspace() {
</WorkspaceFilterPanel> </WorkspaceFilterPanel>
<Card className="v2-vehicle-recent-card" bodyStyle={{ padding: 0 }}> <Card className="v2-vehicle-recent-card" bodyStyle={{ padding: 0 }}>
<WorkspacePanelHeader <WorkspacePanelHeader
title={deferredKeyword ? '匹配车辆' : '授权车辆目录'} title={deferredKeyword ? '匹配车辆' : mobileLayout ? '授权车辆' : '授权车辆目录'}
description={deferredKeyword ? '按当前搜索条件展示,可直接进入车辆数字档案' : '按照最新上报时间排列,分页浏览全部授权车辆'} description={deferredKeyword ? '按当前搜索条件展示,可直接进入车辆数字档案' : '按照最新上报时间排列,分页浏览全部授权车辆'}
meta={<Tag color={deferredKeyword ? 'blue' : 'grey'} type="light" size="small">{candidates.data ? `本页 ${formatZhNumber(pageVehicles.length)}` : '授权范围'}</Tag>} meta={<Tag color={deferredKeyword ? 'blue' : 'grey'} type="light" size="small">{candidates.data ? `本页 ${formatZhNumber(pageVehicles.length)}` : '授权范围'}</Tag>}
actions={<Button theme="borderless" type="tertiary" size="small" icon={<IconRefresh />} loading={candidates.isFetching} onClick={() => candidates.refetch()}></Button>} actions={<Button theme="borderless" type="tertiary" size="small" icon={<IconRefresh />} loading={candidates.isFetching} onClick={() => candidates.refetch()}></Button>}

View File

@@ -2260,12 +2260,38 @@
@media (max-width: 700px) { @media (max-width: 700px) {
.v2-vehicle-search-page { .v2-vehicle-search-page {
gap: 9px; gap: 8px;
padding: 9px 8px 92px; padding: 9px 8px 92px;
} }
.v2-vehicle-command-bar.is-mobile-admin {
min-height: 50px;
border-color: #dce6f2;
background: linear-gradient(105deg, #fff 0%, #f8fbff 100%);
}
.v2-vehicle-command-bar.is-mobile-admin .v2-workspace-command-copy > .semi-typography:last-child {
display: none;
}
.v2-vehicle-command-bar.is-mobile-admin .v2-workspace-command-actions > .semi-button {
min-height: 36px;
border-radius: 9px;
padding-inline: 11px;
}
.v2-vehicle-search-page > .v2-mobile-filter-toggle.semi-button {
min-height: 52px;
padding-block: 6px;
}
.v2-vehicle-query-panel.is-mobile-collapsed {
display: none;
}
.v2-vehicle-query-panel .v2-vehicle-search-form { .v2-vehicle-query-panel .v2-vehicle-search-form {
min-height: 0; min-height: 0;
flex-wrap: wrap;
border-top: 0; border-top: 0;
padding: 9px; padding: 9px;
} }
@@ -8331,10 +8357,6 @@
min-height: 48px; min-height: 48px;
} }
.v2-vehicle-query-panel > .semi-card-body > .v2-workspace-filter-heading {
display: flex;
}
.v2-vehicle-query-panel .v2-vehicle-search-form { .v2-vehicle-query-panel .v2-vehicle-search-form {
height: auto; height: auto;
min-height: 0; min-height: 0;