MUD6 推广移动统一设计

这个提交包含在:
2026-05-12 00:07:24 +08:00
父节点 6359612cd0
当前提交 53a7779a70
共修改 22 个文件,包含 677 行新增和 89 行删除
+21 -20
查看文件
@@ -16,6 +16,7 @@ import { useAuth } from "../auth/AuthContext";
import { hasPermission } from "../auth/permissions";
import { PageHeader } from "../components/common/PageHeader";
import { BarcodeScannerPanel } from "../components/mobile/BarcodeScannerPanel";
import { PageScaffold } from "../components/patterns/PageScaffold";
import { Button } from "../components/ui/button";
import { Input } from "../components/ui/input";
import {
@@ -394,7 +395,7 @@ export function MobileAssetScanPage() {
);
return (
<div className="space-y-4">
<PageScaffold className="space-y-4">
<PageHeader
title={isInventoryMode ? "移动扫码盘点" : "移动资产扫码"}
subtitle={isInventoryMode ? "在盘点任务上下文中扫码定位资产并快捷录入结果。" : "扫码或手工输入资产编号,快速查看资产卡片。"}
@@ -410,7 +411,7 @@ export function MobileAssetScanPage() {
) : null}
{isInventoryMode ? (
<div className="card-std space-y-3 p-4" data-testid="mobile-asset-scan-inventory-context">
<div className="mobile-card space-y-3" data-testid="mobile-asset-scan-inventory-context">
<div className="flex items-center justify-between gap-3">
<div>
<h3 className="text-base font-semibold text-zinc-900">盘点任务上下文</h3>
@@ -436,7 +437,7 @@ export function MobileAssetScanPage() {
) : null}
{selectedInventoryCheck ? (
<div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-zinc-200 px-3 py-3 text-sm">
<div className="mobile-list-card flex flex-wrap items-center justify-between gap-3 text-sm">
<div>
<div className="font-medium text-zinc-900">{selectedInventoryCheck.checkNo}</div>
<div className="text-zinc-500">状态:{inventoryStatusLabel(selectedInventoryCheck.status)} · 范围:{selectedInventoryCheck.scopeType} / {selectedInventoryCheck.scopeRefId ?? "全量"}</div>
@@ -459,13 +460,13 @@ export function MobileAssetScanPage() {
}}
/>
<div className="card-std space-y-3 p-4" data-testid="mobile-asset-scan-search">
<div className="mobile-card space-y-3" data-testid="mobile-asset-scan-search">
<div className="flex items-center justify-between gap-3">
<h3 className="text-base font-semibold text-zinc-900">手工输入 / 搜索</h3>
<span className={`text-sm ${isOnline ? "text-emerald-600" : "text-orange-600"}`}>{isOnline ? "在线" : "离线"}</span>
</div>
<div className="flex flex-col gap-2 sm:flex-row">
<div className="grid gap-2 min-[390px]:grid-cols-[minmax(0,1fr)_auto]">
<Input
data-testid="mobile-asset-scan-input"
value={searchInput}
@@ -483,14 +484,14 @@ export function MobileAssetScanPage() {
</div>
{filteredSearchResults.length > 1 ? (
<div className="card-std space-y-3 p-4" data-testid="mobile-asset-scan-candidates">
<div className="mobile-card space-y-3" data-testid="mobile-asset-scan-candidates">
<h3 className="text-base font-semibold text-zinc-900">候选资产</h3>
<div className="space-y-2">
{filteredSearchResults.map((item) => (
<button
key={item.id}
type="button"
className={`w-full rounded-lg border px-3 py-3 text-left text-sm ${selectedAssetId === item.id ? "border-primary bg-primary-50 text-primary" : "border-zinc-200 bg-white text-zinc-800"}`}
className={`mobile-list-card w-full text-left text-sm ${selectedAssetId === item.id ? "border-primary bg-primary-50 text-primary" : "border-zinc-200 bg-white text-zinc-800"}`}
onClick={() => setSelectedAssetId(item.id)}
data-testid={`mobile-asset-scan-candidate-${item.id}`}
>
@@ -503,7 +504,7 @@ export function MobileAssetScanPage() {
) : null}
{selectedAsset ? (
<div className="card-std space-y-4 p-4" data-testid="mobile-asset-scan-detail">
<div className="mobile-card space-y-4" data-testid="mobile-asset-scan-detail">
<div className="flex flex-wrap items-start justify-between gap-3">
<div>
<h3 className="text-lg font-semibold text-zinc-900">{selectedAsset.assetNo}</h3>
@@ -514,22 +515,22 @@ export function MobileAssetScanPage() {
</Button>
</div>
<div className="grid gap-3 md:grid-cols-2">
<div className="rounded-lg border border-zinc-200 px-3 py-2 text-sm">状态:{statusLabel(selectedAsset.status)}</div>
<div className="rounded-lg border border-zinc-200 px-3 py-2 text-sm">法体:{selectedAsset.legalEntity?.name ?? "-"}</div>
<div className="rounded-lg border border-zinc-200 px-3 py-2 text-sm">成本中心:{selectedAsset.costCenter?.name ?? "-"}</div>
<div className="rounded-lg border border-zinc-200 px-3 py-2 text-sm">位置:{selectedAsset.location ?? "-"}</div>
<div className="rounded-lg border border-zinc-200 px-3 py-2 text-sm">归属人:{selectedAsset.assignee?.name ?? "未分配"}</div>
<div className="rounded-lg border border-zinc-200 px-3 py-2 text-sm">序列号:{selectedAsset.serialNo ?? "-"}</div>
<div className="mobile-info-grid">
<div className="mobile-subcard text-sm">状态:{statusLabel(selectedAsset.status)}</div>
<div className="mobile-subcard text-sm">法体:{selectedAsset.legalEntity?.name ?? "-"}</div>
<div className="mobile-subcard text-sm">成本中心:{selectedAsset.costCenter?.name ?? "-"}</div>
<div className="mobile-subcard text-sm">位置:{selectedAsset.location ?? "-"}</div>
<div className="mobile-subcard text-sm">归属人:{selectedAsset.assignee?.name ?? "未分配"}</div>
<div className="mobile-subcard text-sm">序列号:{selectedAsset.serialNo ?? "-"}</div>
</div>
{isInventoryMode && canRecordInventory && selectedInventoryCheck ? (
<div className="space-y-3 rounded-xl border border-zinc-200 bg-zinc-50 p-4">
<div className="mobile-subcard space-y-3 bg-zinc-50">
<div>
<h4 className="text-sm font-semibold text-zinc-900">盘点录入</h4>
<p className="text-xs text-zinc-500">仅在盘点中的任务可提交或离线缓存结果。</p>
</div>
<div className="grid gap-3 md:grid-cols-2">
<div className="mobile-info-grid">
<div className="space-y-2">
<label className="text-sm font-medium text-zinc-700">盘点结果</label>
<select className="select-std" value={recordResult} onChange={(event) => setRecordResult(event.target.value as InventoryCheckResult)}>
@@ -564,7 +565,7 @@ export function MobileAssetScanPage() {
) : null}
{isInventoryMode && canRecordInventory ? (
<div className="card-std space-y-3 p-4" data-testid="mobile-asset-scan-queue">
<div className="mobile-card space-y-3" data-testid="mobile-asset-scan-queue">
<div className="flex items-center justify-between gap-3">
<h3 className="text-base font-semibold text-zinc-900">离线盘点队列</h3>
<span className="text-sm text-zinc-500">{currentQueueItems.length ? `待同步 ${currentQueueItems.length} 项` : "无待同步项"}</span>
@@ -575,7 +576,7 @@ export function MobileAssetScanPage() {
) : null}
{currentQueueItems.map((item) => (
<div key={item.id} className="rounded-lg border border-zinc-200 px-3 py-3 text-sm">
<div key={item.id} className="mobile-list-card text-sm">
<div className="font-medium text-zinc-900">{item.assetNo}</div>
<div className="text-zinc-500">结果:{inventoryResultLabel(item.result)} · 创建时间:{formatDateTime(item.createdAt)}</div>
<div className="text-zinc-500">备注:{item.note ?? "-"}</div>
@@ -597,6 +598,6 @@ export function MobileAssetScanPage() {
))}
</div>
) : null}
</div>
</PageScaffold>
);
}