کارت کار (JobCard)

یک کار async — تحلیل، خزش، ورود فایل — با مرحله، صف، پیشرفت شمارشی، علت شکست و یک اقدام اصلی برای هر مرحله، در سه چیدمان کارت، ردیف و سربرگ صفحه.

معرفی

JobCard هر کار async را نشان می‌دهد: تحلیل کامنت، ارزیابی صفحه، ورود فایل، تولید گزارش. داده‌ی کار را بدهید، سیستم طراحی آن را می‌چیند: برچسب و رنگ وضعیت، نوار پیشرفت، جمله‌ی مرحله یا علت شکست، و فقط یک اقدام اصلی متناسب با مرحله (بازبینی، تلاش مجدد، آپلود مجدد، لغو) به‌همراه منوی «بیشتر». اقدام‌ها هیچ‌وقت داخل لینک باز شدن کارت نیستند.

از 4.0 JobCard فقط از زیرمسیر وارد می‌شود: @partodata/ui/job-card (یا @partodata/ui/social کنار EntityCollection).

چه زمانی استفاده کنیم:

  • فهرست «تحلیل‌های من» / «کارها» در داشبورد، به‌صورت کارت یا ردیف (EntityCollection entity="job")
  • سربرگ صفحه‌ی نتیجه‌ی یک کار در حال اجرا (layout="header")
  • صف کارهای مدیریتی با سازنده و هزینه

چه زمانی استفاده نکنیم:

  • نمایش محتوا — پست: Post، حساب: Account
  • متریک تک‌عدد با روند — MetricCard
  • مراحل یک فرایند چندگامی که کاربر پر می‌کند — WizardPage

تحلیل کامنت‌های کمپین تخفیف فصلی

در حال برچسب‌گذاری#6
62٪
1250
کامنت
هوشمند@sample_shopدر حال محاسبه…
در حال اجرا
چند منبع

بازخورد بسته‌بندی جدید

نیازمند بازبینی شما#5

نتیجه آماده است و منتظر بازبینی شماست.

842
کامنت
12
برچسب
یکپارچه3 منبع
نیازمند بازبینی شما

استفاده

'use client'
import { JobCard } from '@partodata/ui/job-card'

export function AnalysisCard({ job }) {
  return (
    <JobCard
      phase={job.phase}              // 'queued' | 'running' | 'needs-action' | 'failed' | …
      stage={job.stageLabel}         // «در حال برچسب‌گذاری»
      title={job.title}
      jobRef={`#${job.number}`}
      target={{ kind: 'post', platform: 'instagram', image: job.thumbnail }}
      progress={{ done: job.done, total: job.total, failed: job.failed, unit: 'پست' }}
      queue={{ position: job.queuePosition, etaMinutes: job.eta }}
      failure={job.error ? { reason: job.error, stage: job.errorStage, retryable: job.retryable } : undefined}
      createdAt={job.createdAt}
      counts={[{ label: 'کامنت', value: job.comments }]}
      href={`/analyses/${job.id}`}
      onRetry={() => retry(job.id)}
      onCancel={() => cancel(job.id)}
      onReview={() => router.push(`/analyses/${job.id}/review`)}
      menu={[{ id: 'delete', label: 'حذف', tone: 'destructive', onSelect: () => remove(job.id) }]}
    />
  )
}

مرحله‌ها

phase: draft | queued | running | needs-action | paused | completed | partial | failed | cancelled | expired

حساب

ارزیابی 8 صفحه‌ی تبلیغاتی

در صف#12
نفر 3 در صفحدود 5 دقیقه
@brand.studio
در صف

تحلیل کامنت‌های رونمایی محصول

در حال دریافت کامنت‌ها#11
2 از 5 پستآخرین به‌روزرسانی 46 ثانیه پیش
در حال اجرا
چند منبع

برچسب‌های پیشنهادی کمپین پاییز

نیازمند بازبینی شما#10

نتیجه آماده است و منتظر بازبینی شماست.

نیازمند بازبینی شما
فایل

ورود فایل کامنت‌ها

خطا — پردازش فایل#8

ستون «متن کامنت» در فایل پیدا نشد.

comments-mehr.xlsx
ناموفق
پست

تحلیل ساده‌ی پست معرفی

لغو شد#4

این کار لغو شد و نتیجه‌ای ندارد.

لغو شد

تحلیل کامنت‌های ماه گذشته

منقضی شد#3

داده‌های این کار منقضی شده است.

منقضی شد

تحلیل جدید

پیش‌نویس

هنوز ارسال نشده است.

پیش‌نویس
  • برچسب وضعیت = نام مرحله در حال اجرا (stage)، «خطا — {مرحله}» در شکست، «نفر n در صف · حدود m دقیقه» در صف.
  • اقدام اصلی را سیستم طراحی انتخاب می‌کند: needs-action → بازبینی؛ failed → تلاش مجدد (یا آپلود مجدد برای هدف فایل)؛ partial → تلاش مجدد برای ناموفق‌ها؛ صف و اجرا → لغو؛ تمام‌شده → بدون دکمه (کل کارت باز می‌شود).
  • رنگ فقط در نوار 2 پیکسلی لبه‌ی آغاز کارت و نشان وضعیت: اجرا برند، نیازمند اقدام و جزئی هشدار، شکست قرمز؛ کارت‌های تمام‌شده آرام‌ترین‌اند.
  • پیشرفت هرگز عقب نمی‌رود؛ با done/total/failed نوار بخش‌بندی‌شده و «2 از 5 پست · 1 ناموفق». در صف و اجرا کارت باز نمی‌شود مگر openWhileRunning.
  • زنده بودن: با live={{ updatedAt }}، اگر بیش از 30 ثانیه به‌روزرسانی نرسد متن «آخرین به‌روزرسانی … پیش» نمایش داده می‌شود (نه قرمز).

ردیف در فهرست

پست

تحلیل کامنت‌های کانال خبری نمونه

#1
در حال تحلیل احساسات
در حال اجرا
پست

ارزیابی 8 صفحه‌ی تبلیغاتی

#2
در صف
در صف

EntityCollection entity="job" چیدمان‌های card و row، اسکلتون، انتخاب گروهی و حرکت با کلیدهای جهت را آماده دارد.

سربرگ صفحه‌ی نتیجه

تحلیل کامنت‌های کمپین تخفیف فصلی

در حال برچسب‌گذاری#6
هوشمند@sample_shopدر حال محاسبه…
60٪
در حال اجرا

زمین بازی

زمین بازی
پست

تحلیل گفت‌وگوهای کمپین

در حال برچسب‌گذاری
64٪
1200
پست‌ها
5300
کامنت‌ها
@sample_shop
در حال اجرا
تنظیمات
حالت
ظاهر
محتوا
داده
64
کد این نمونه به‌صورت خودکار قابل تولید نیست — برای کد آماده‌ی copy/paste به بخش «استفاده» در بالای صفحه مراجعه کنید.

progress نامعین (indeterminate)

حساب

واکشی پروفایل از اینستاگرام

در حال اتصال…
@sample_shop
در حال اجرا

وقتی کار در حال انجام است ولی درصد پیشرفت مشخص نیست (مثل «منتظر پاسخ API»)، progress را ندهید یا value را خالی بگذارید: نوار نامعین می‌شود. shimmer از start به end حرکت می‌کند و با prefers-reduced-motion ساکن می‌شود.

thumbnail با تصویر

تحلیل کامنت‌های پست کافه لاکچری

تکمیل شد
3420
موافق کمپین
680
مخالف
1200
خنثی
@cafe_lux
تکمیل شد
  • target.image تصویر هدف کار است (مثلاً پیش‌نمایش پست)؛ اگر بار نشود یا نباشد، نشانهٔ نوع هدف (target.kind) جایش می‌نشیند

ترکیب با FilterPanel برای صفحه Jobs

در صفحه‌ی مدیریت کارها (مثل «تحلیل‌های من»)، الگوی کامل معمولاً این شکل است:

<div className="flex gap-6">
  <aside className="w-72">
    <FilterPanel>
      <FilterPanelHeader>
        <FilterPanelTitle activeCount={activeCount} />
      </FilterPanelHeader>
      <FilterPanelBody>
        <FilterSection title="مرحله">{/* checkboxes for JobPhase */}</FilterSection>
        <FilterSection title="بازه زمانی">{/* DateRangePicker */}</FilterSection>
      </FilterPanelBody>
    </FilterPanel>
  </aside>
  <div className="flex flex-1 flex-col gap-3">
    {jobs.map((job) => (
      <JobCard key={job.id} layout="row" {...job} onOpen={() => open(job.id)} />
    ))}
  </div>
</div>

Props

JobCard

Prop

Type

راهنمای استفاده

بکنید

  • مراحل کار خودتان را به phase نگاشت کنید (CommentSanj pending_review → running با stage اختصاصی). چرخهٔ عمر را با همین مرحله‌ها مدل کنید، نه برعکس.
  • در completed نتیجه را با counts نشان دهید (حداکثر سه عدد؛ total «x از y» می‌نویسد)، نه با پیشرفت.
  • در failed همیشه failure.reason بدهید تا کاربر دلیل و قدم بعد (onRetry) را بداند.
  • برای فهرست بلند layout="row" و onOpen یا href؛ جزئیات را در صفحهٔ جدا یا Drawer باز کنید.

نکنید

  • مرحلهٔ سفارشی به JobPhase اضافه نکنید؛ زیرمرحله را با stage بنویسید.
  • برای پیشرفت چندمرحله‌ای (pipeline) از این استفاده نکنید؛ StatusFlow برای آن است.

دسترسی‌پذیری

  • با onOpen یا href کل کارت یک دکمه یا پیوند واقعی است؛ دکمه‌های اقدام کارت مستقل می‌مانند.
  • نوار پیشرفت role="progressbar" با aria-valuenow/min/max است؛ وقتی مقدار نامعلوم است aria-valuenow ندارد.
  • انیمیشن‌ها (چرخش و shimmer) با prefers-reduced-motion ساکن می‌شوند.

کامپوننت‌های مرتبط

  • Post — پست شبکه اجتماعی، خبر یا بخش پخش؛ از این برای محتوا استفاده کنید، از JobCard برای کار
  • MetricCard — کارت متریک تک‌عدد با trend؛ برای KPI ها
  • Card — کارت سطح پایین بدون semantic ویژه
  • SeverityBadge — badge وضعیت operational (critical/warning/middle/low) — مستقل از lifecycle کار
  • FilterPanel — برای فیلتر کردن لیست کارها
  • StatusFlow — برای نمایش pipeline چندمرحله‌ای داخل کار