R97 B1-B5 精修高频页面操作密度

这个提交包含在:
2026-05-06 17:56:57 +08:00
父节点 4cfac0ddf8
当前提交 705cf1e361
共修改 7 个文件,包含 226 行新增和 151 行删除
+64 -57
查看文件
@@ -771,66 +771,73 @@ export function MobileApprovalsPage() {
</TabsList>
</Tabs>
<Tabs value={entityFilter} onValueChange={(value) => setEntityFilter(value as EntityFilter)}>
<TabsList className="flex w-full flex-wrap justify-start gap-1">
{ENTITY_FILTER_OPTIONS.map((option) => (
<TabsTrigger key={option.value} value={option.value}>
{option.label}
</TabsTrigger>
))}
</TabsList>
</Tabs>
<div className="space-y-3">
<Input
data-testid="mobile-approvals-search"
value={searchInput}
onChange={(event) => setSearchInput(event.target.value)}
placeholder="搜索步骤名、业务类型、任务 ID 或业务实体 ID"
placeholder="搜索待办"
/>
{taskTab === "pending" ? (
<div className="grid gap-2 sm:flex sm:flex-wrap sm:items-center">
<Button
type="button"
size="sm"
variant={batchMode ? "default" : "secondary"}
className="min-h-11 w-full sm:w-auto"
disabled={!filteredTaskCards.length}
onClick={() => {
setBatchMode((current) => !current);
setSelectedBatchTaskIds([]);
setBatchRejectComment("");
}}
>
{batchMode ? "退出批量处理" : "批量处理"}
</Button>
{batchMode ? (
<Button
type="button"
size="sm"
variant="secondary"
className="min-h-11 w-full sm:w-auto"
disabled={!filteredTaskCards.length}
onClick={toggleSelectAllVisibleTasks}
>
{allVisibleSelected ? "清空选择" : "全选当前筛选结果"}
</Button>
) : null}
<span className="text-sm text-zinc-500 sm:ml-1">
当前结果 {filteredTaskCards.length} 条
{batchMode ? `,已选 ${selectedBatchTaskIds.length} 条` : ""}
</span>
<details className="rounded-xl border border-zinc-200 bg-zinc-50/70 px-3 py-2 text-sm">
<summary className="cursor-pointer select-none font-medium text-zinc-700">
筛选与批量
</summary>
<div className="mt-3 space-y-3">
<Tabs value={entityFilter} onValueChange={(value) => setEntityFilter(value as EntityFilter)}>
<TabsList className="flex w-full flex-wrap justify-start gap-1">
{ENTITY_FILTER_OPTIONS.map((option) => (
<TabsTrigger key={option.value} value={option.value}>
{option.label}
</TabsTrigger>
))}
</TabsList>
</Tabs>
{taskTab === "pending" ? (
<div className="grid gap-2 sm:flex sm:flex-wrap sm:items-center">
<Button
type="button"
size="sm"
variant={batchMode ? "default" : "secondary"}
className="min-h-11 w-full sm:w-auto"
disabled={!filteredTaskCards.length}
onClick={() => {
setBatchMode((current) => !current);
setSelectedBatchTaskIds([]);
setBatchRejectComment("");
}}
>
{batchMode ? "退出批量" : "批量"}
</Button>
{batchMode ? (
<Button
type="button"
size="sm"
variant="secondary"
className="min-h-11 w-full sm:w-auto"
disabled={!filteredTaskCards.length}
onClick={toggleSelectAllVisibleTasks}
>
{allVisibleSelected ? "清空选择" : "全选当前"}
</Button>
) : null}
<span className="text-sm text-zinc-500 sm:ml-1">
当前 {filteredTaskCards.length} 条
{batchMode ? `,已选 ${selectedBatchTaskIds.length}` : ""}
</span>
</div>
) : (
<p className="text-sm text-zinc-500">仅显示最近 30 天。</p>
)}
</div>
) : (
<p className="text-sm text-zinc-500">已处理页仅展示最近 30 天内的 completed 任务。</p>
)}
</details>
</div>
{batchMode ? (
<div className="rounded-2xl border border-zinc-200 bg-zinc-50 p-3 text-sm">
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="text-zinc-700">已选择 {selectedBatchTaskIds.length} 条待办,可在线串行处理或离线逐条入队。</div>
<div className="text-zinc-700">已选 {selectedBatchTaskIds.length} 条</div>
<div className="grid w-full gap-2 sm:flex sm:w-auto sm:flex-wrap">
<Button
type="button"
@@ -839,7 +846,7 @@ export function MobileApprovalsPage() {
disabled={!selectedBatchTaskIds.length || batchActionMutation.isPending}
onClick={() => handleBatchAction("approve")}
>
{canUseRemote ? "批量通过" : "离线批量加入通过草稿"}
{canUseRemote ? "批量通过" : "加入通过草稿"}
</Button>
<Button
type="button"
@@ -849,7 +856,7 @@ export function MobileApprovalsPage() {
disabled={!selectedBatchTaskIds.length || batchActionMutation.isPending || !batchRejectComment.trim()}
onClick={() => handleBatchAction("reject")}
>
{canUseRemote ? "批量驳回" : "离线批量加入驳回草稿"}
{canUseRemote ? "批量驳回" : "加入驳回草稿"}
</Button>
</div>
</div>
@@ -920,7 +927,7 @@ export function MobileApprovalsPage() {
<div className="font-medium text-zinc-900">{task.title}</div>
<StatusBadge status={task.status} label={workflowStatusLabel(task.status)} />
</div>
<div className="mt-1 text-xs text-zinc-500">任务:{task.id}</div>
<div className="mt-1 text-xs text-zinc-500">任务:{task.id}</div>
<div className="mt-1 text-xs text-zinc-500">{task.subtitle}</div>
{task.isCached ? <div className="mt-1 text-xs text-zinc-500">来源:离线缓存</div> : null}
</button>
@@ -955,7 +962,7 @@ export function MobileApprovalsPage() {
</section>
<section ref={detailSectionRef} className="card-std scroll-mt-4 space-y-3 p-4" data-testid="mobile-approvals-detail">
<h3 className="text-base font-semibold text-zinc-900">详情与处理</h3>
<h3 className="text-base font-semibold text-zinc-900">处理</h3>
{!selectedTaskId ? <p className="text-sm text-zinc-500">请先选择任务。</p> : null}
@@ -1025,13 +1032,13 @@ export function MobileApprovalsPage() {
<Textarea
data-testid="mobile-approvals-comment"
onChange={(event) => setComment(event.target.value)}
placeholder="驳回 / 退回意见;离线仅支持驳回意见入队。"
placeholder="意见(驳回/退回必填)"
rows={3}
value={comment}
/>
{!canUseRemote ? (
<p className="text-xs text-zinc-500">离线状态下仅支持通过 / 驳回草稿,退回与转审需联网执行。</p>
<p className="text-xs text-zinc-500">离线仅支持通过 / 驳回草稿。</p>
) : null}
<div className="grid gap-2 sm:grid-cols-3">
@@ -1123,8 +1130,8 @@ export function MobileApprovalsPage() {
<section className="card-std space-y-3 p-4" data-testid="mobile-approvals-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>
<h3 className="text-base font-semibold text-zinc-900">离线草稿</h3>
<span className="text-sm text-zinc-500">{currentQueueItems.length ? `待同步 ${currentQueueItems.length}` : "无草稿"}</span>
</div>
{currentQueueItems.length ? (
@@ -1137,12 +1144,12 @@ export function MobileApprovalsPage() {
type="button"
variant="secondary"
>
{syncMutation.isPending ? "同步中..." : `同步草稿队列 (${retryableQueueItems.length})`}
{syncMutation.isPending ? "同步中..." : `同步草稿 (${retryableQueueItems.length})`}
</Button>
</div>
) : null}
{!currentQueueItems.length ? <p className="text-sm text-zinc-500">暂无待同步审批草稿。</p> : null}
{!currentQueueItems.length ? <p className="text-sm text-zinc-500">暂无待同步草稿。</p> : null}
{currentQueueItems.map((item) => (
<div key={item.id} className="rounded-lg border border-zinc-200 px-3 py-3 text-sm">