feat(tasks): 切换页加「获取最新任务中」刷新状态 + 旋转动画,1.2s 后切换

- TaskDisplay.jsx:displayedPage 与 page 分离,页切换先置 switching 展示加载遮罩,SWITCH_MS(1200ms) 后再切到新页;task_refresh 亦播放一次。
- task-display.css:tasks-screen position:relative;+ tasks-switch-overlay / tasks-spinner(旋转) / tasks-switch-text。

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Pine
2026-08-25 20:21:18 +08:00
parent b00ecbdca1
commit 327e09c2a0
2 changed files with 64 additions and 4 deletions
+31 -4
View File
@@ -43,6 +43,9 @@ export default function TaskDisplay() {
const pageSize = cols * ROWS; // 2×2=4 或 2×3=6
const pageCount = Math.max(1, Math.ceil(tasks.length / pageSize));
const [countdown, setCountdown] = useState(Math.round(ROTATE_MS / 1000));
// 切换:page 为目标页,displayedPage 为当前展示页;切换时先显示「获取最新任务中」动画,1-2 秒后再切
const [displayedPage, setDisplayedPage] = useState(0);
const [switching, setSwitching] = useState(false);
useEffect(() => {
if (pageCount <= 1) { setPage(0); return; }
const t = setInterval(() => setPage((p) => (p + 1) % pageCount), ROTATE_MS);
@@ -56,13 +59,30 @@ export default function TaskDisplay() {
return () => clearInterval(t);
}, []);
// 页切换 → 显示加载动画,SWITCH_MS 后再切到新页
const SWITCH_MS = 1200;
useEffect(() => {
if (page === displayedPage) return;
setSwitching(true);
const t = setTimeout(() => { setDisplayedPage(page); setSwitching(false); }, SWITCH_MS);
return () => clearTimeout(t);
}, [page, displayedPage]);
// 手动/任务刷新 → 同样播放一次「获取最新任务中」
useEffect(() => {
if (refreshTick === 0) return;
setSwitching(true);
const t = setTimeout(() => setSwitching(false), SWITCH_MS);
return () => clearTimeout(t);
}, [refreshTick]);
const visible = useMemo(() => {
if (tasks.length === 0) return [];
const start = page * pageSize;
const start = displayedPage * pageSize;
// 不足一页时按行补位(循环取),保证 2 行填满
const items = tasks.slice(start, start + pageSize);
return items.length ? items : Array.from({ length: pageSize }, (_, i) => tasks[i % tasks.length]);
}, [tasks, page, pageSize]);
}, [tasks, displayedPage, pageSize]);
return (
<div className="tasks-screen">
@@ -76,7 +96,7 @@ export default function TaskDisplay() {
<span className="tasks-info-sep">·</span>
<span className="tasks-info">翻页 <b>{pageCount > 1 ? `${countdown}s` : '—'}</b></span>
<span className="tasks-info-sep">·</span>
<span className="tasks-info">页码 <b>{pageCount > 1 ? `${page + 1}/${pageCount}` : '1/1'}</b></span>
<span className="tasks-info">页码 <b>{pageCount > 1 ? `${displayedPage + 1}/${pageCount}` : '1/1'}</b></span>
<span className="tasks-info-sep">·</span>
<span className="tasks-info hint">接单:抢单·竞标·指派·推荐</span>
</div>
@@ -99,10 +119,17 @@ export default function TaskDisplay() {
{pageCount > 1 && (
<div className="tasks-dots">
{Array.from({ length: pageCount }).map((_, i) => (
<span key={i} className={i === page ? 'tasks-dot on' : 'tasks-dot'} />
<span key={i} className={i === displayedPage ? 'tasks-dot on' : 'tasks-dot'} />
))}
</div>
)}
{/* 切换/刷新加载遮罩 */}
{switching && (
<div className="tasks-switch-overlay">
<span className="tasks-spinner" />
<span className="tasks-switch-text">获取最新任务中…</span>
</div>
)}
</>
)}
</div>
+33
View File
@@ -8,6 +8,7 @@
width: 100%;
height: 100%;
overflow: hidden;
position: relative; /* 供切换加载遮罩定位于此 */
background: radial-gradient(ellipse at 20% 0%, rgba(79, 135, 255, 0.08), transparent 55%),
radial-gradient(ellipse at 80% 100%, rgba(23, 178, 106, 0.06), transparent 55%);
}
@@ -115,3 +116,35 @@
.task-dots { display: flex; justify-content: center; gap: 8px; padding-bottom: 6px; }
.task-dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(29, 44, 68, 0.15); transition: all 0.25s; }
.task-dot.on { background: var(--bd-blue, #2f6bff); width: 20px; border-radius: 999px; }
/* ---- 切换/刷新加载遮罩:文字(获取最新任务中) + 旋转动画 ---- */
.tasks-switch-overlay {
position: absolute;
inset: 0;
z-index: 5;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 14px;
background: rgba(255, 255, 255, 0.72);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
}
.tasks-spinner {
width: 42px;
height: 42px;
border-radius: 50%;
border: 4px solid rgba(47, 107, 255, 0.18);
border-top-color: var(--bd-blue, #2f6bff);
animation: tasks-spin 0.8s linear infinite;
}
.tasks-switch-text {
font-size: 15px;
font-weight: 600;
color: var(--bd-blue, #2f6bff);
letter-spacing: 0.05em;
}
@keyframes tasks-spin {
to { transform: rotate(360deg); }
}