优化考核调研首页移动端体验
This commit is contained in:
parent
ab2e31f01a
commit
d428eb96a6
@ -289,50 +289,89 @@ function Dashboard() {
|
||||
const surveys = useApi<any>('/surveys', [])
|
||||
const me = useApi<any>('/me', [])
|
||||
const canManage = Boolean(me.data?.permissions?.isDepartmentAdmin)
|
||||
const pendingItems = surveys.data?.pending || []
|
||||
const createdItems = surveys.data?.created || []
|
||||
const resultItems = surveys.data?.results || []
|
||||
const openTotal = createdItems.filter((item: any) => item.status === 'open').length
|
||||
const responseTotal = createdItems.reduce((sum: number, item: any) => sum + Number(item.counts?.responses || 0), 0)
|
||||
const displayName = me.data?.employee?.displayName || me.data?.employee?.flowerName || me.data?.user?.name || '当前用户'
|
||||
const avatarUrl = me.data?.user?.avatar || ''
|
||||
const avatarInitial = String(displayName || '用').trim().charAt(0).toUpperCase() || '用'
|
||||
const departmentLabel = me.data?.employee?.departmentName || me.data?.user?.department || '未同步部门'
|
||||
const positionLabel = [me.data?.employee?.positionTitle, me.data?.employee?.positionLevel].filter(Boolean).join(' · ')
|
||||
|
||||
const tabs = [
|
||||
{ id: 'pending', label: '待我评价' },
|
||||
{ id: 'created', label: '我发起的' },
|
||||
{ id: 'results', label: '我的结果' },
|
||||
...(canManage ? [{ id: 'manage', label: '管理' }] : []),
|
||||
{ id: 'pending', label: '待我评价', count: pendingItems.length },
|
||||
{ id: 'created', label: '我发起的', count: createdItems.length },
|
||||
{ id: 'results', label: '我的结果', count: resultItems.length },
|
||||
...(canManage ? [{ id: 'manage', label: '管理', count: undefined }] : []),
|
||||
]
|
||||
|
||||
return (
|
||||
<main className="mx-auto max-w-7xl px-4 py-6">
|
||||
<div className="mb-5 flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold text-gray-900 dark:text-white">考核调研</h1>
|
||||
<div className="mt-2 flex flex-wrap gap-2 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span>{me.data?.user?.name || '当前用户'}</span>
|
||||
{me.data?.employee?.departmentName && <span>{me.data.employee.departmentName}</span>}
|
||||
{me.data?.employee?.positionLevel && <span>{me.data.employee.positionLevel}</span>}
|
||||
<main className="mx-auto max-w-7xl px-4 py-4 pb-24 sm:py-6 md:pb-6">
|
||||
<section className="mb-4 overflow-hidden rounded-[28px] border border-[#dfe7f2] bg-white shadow-[0_18px_48px_rgba(15,23,42,0.08)] dark:border-gray-700 dark:bg-gray-900 sm:rounded-[20px]">
|
||||
<div className="bg-[#0e1728] px-5 py-5 text-white sm:px-6">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="min-w-0">
|
||||
<div className="text-sm font-medium text-white/65">考核调研</div>
|
||||
<h1 className="mt-2 text-[2rem] font-semibold leading-tight tracking-normal sm:text-2xl">我的调研工作台</h1>
|
||||
<div className="mt-3 flex flex-wrap items-center gap-2 text-sm text-white/72">
|
||||
<span className="max-w-[12rem] truncate font-medium text-white">{displayName}</span>
|
||||
<span className="h-1 w-1 rounded-full bg-white/35" />
|
||||
<span className="max-w-[14rem] truncate">{departmentLabel}</span>
|
||||
{positionLabel && (
|
||||
<>
|
||||
<span className="h-1 w-1 rounded-full bg-white/35" />
|
||||
<span>{positionLabel}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex h-14 w-14 shrink-0 items-center justify-center overflow-hidden rounded-full border border-white/25 bg-white/10 text-lg font-semibold text-white shadow-inner">
|
||||
{avatarUrl ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img src={avatarUrl} alt={displayName} className="h-full w-full object-cover" />
|
||||
) : (
|
||||
avatarInitial
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 grid grid-cols-3 gap-2">
|
||||
<DashboardMetric label="待评价" value={pendingItems.length} emphasis />
|
||||
<DashboardMetric label="进行中" value={openTotal} />
|
||||
<DashboardMetric label="已提交" value={responseTotal} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex rounded-lg border border-gray-200 bg-white p-1 dark:border-gray-700 dark:bg-gray-800">
|
||||
<div className="flex gap-1 overflow-x-auto px-3 py-3 sm:px-4">
|
||||
{tabs.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => setTab(item.id)}
|
||||
className={`px-3 py-1.5 text-sm rounded-md transition-colors ${
|
||||
className={`min-w-max rounded-2xl px-4 py-2.5 text-sm font-semibold transition-colors ${
|
||||
tab === item.id
|
||||
? 'bg-gray-900 text-white dark:bg-white dark:text-gray-900'
|
||||
: 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'
|
||||
? 'bg-[#111827] text-white shadow-sm dark:bg-white dark:text-gray-900'
|
||||
: 'text-gray-500 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800'
|
||||
}`}
|
||||
>
|
||||
{item.label}
|
||||
{typeof item.count === 'number' && item.count > 0 && (
|
||||
<span className={`ml-2 rounded-full px-1.5 py-0.5 text-xs ${tab === item.id ? 'bg-white/18 text-white dark:bg-gray-900/10 dark:text-gray-900' : 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-300'}`}>
|
||||
{item.count}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{surveys.loading && <Panel>加载中...</Panel>}
|
||||
{surveys.error && <ErrorPanel message={surveys.error} />}
|
||||
{surveys.data && <DashboardStats data={surveys.data} />}
|
||||
{surveys.data && tab === 'pending' && <PendingList items={surveys.data.pending || []} />}
|
||||
{surveys.data && <DashboardStats data={surveys.data} activeTab={tab} />}
|
||||
{surveys.data && tab === 'pending' && <PendingList items={pendingItems} />}
|
||||
{surveys.data && tab === 'created' && (
|
||||
<CreatedList items={surveys.data.created || []} onRefresh={surveys.refresh} />
|
||||
<CreatedList items={createdItems} onRefresh={surveys.refresh} />
|
||||
)}
|
||||
{surveys.data && tab === 'results' && <MyResults items={surveys.data.results || []} />}
|
||||
{surveys.data && tab === 'results' && <MyResults items={resultItems} />}
|
||||
{canManage && tab === 'manage' && (
|
||||
<ManagePanel
|
||||
onChanged={async () => {
|
||||
@ -345,7 +384,16 @@ function Dashboard() {
|
||||
)
|
||||
}
|
||||
|
||||
function DashboardStats({ data }: { data: any }) {
|
||||
function DashboardMetric({ label, value, emphasis }: { label: string; value: number; emphasis?: boolean }) {
|
||||
return (
|
||||
<div className={`rounded-2xl px-3 py-3 ${emphasis ? 'bg-white text-[#0f172a]' : 'bg-white/10 text-white'}`}>
|
||||
<div className={`text-xs ${emphasis ? 'text-gray-500' : 'text-white/60'}`}>{label}</div>
|
||||
<div className="mt-1 text-2xl font-semibold leading-none">{value}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function DashboardStats({ data, activeTab }: { data: any; activeTab: string }) {
|
||||
const created = data.created || []
|
||||
const templateStats = data.templateStats || []
|
||||
const responseTotal = created.reduce((sum: number, item: any) => sum + Number(item.counts?.responses || 0), 0)
|
||||
@ -358,7 +406,7 @@ function DashboardStats({ data }: { data: any }) {
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="mb-5 grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
|
||||
<div className={`mb-5 grid gap-4 sm:grid-cols-2 xl:grid-cols-4 ${activeTab === 'manage' ? '' : 'hidden sm:grid'}`}>
|
||||
{items.map((item) => (
|
||||
<div key={item.label} className="rounded-lg border border-gray-200 bg-white p-5 dark:border-gray-700 dark:bg-gray-800">
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400">{item.label}</div>
|
||||
@ -371,27 +419,34 @@ function DashboardStats({ data }: { data: any }) {
|
||||
|
||||
function PendingList({ items }: { items: any[] }) {
|
||||
if (items.length === 0) {
|
||||
return <EmptyState title="暂无待评价" />
|
||||
return (
|
||||
<div className="rounded-[24px] border border-dashed border-gray-200 bg-white px-5 py-8 text-center shadow-[0_12px_34px_rgba(15,23,42,0.05)] dark:border-gray-700 dark:bg-gray-900 sm:rounded-lg">
|
||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-gray-100 text-lg font-semibold text-gray-500 dark:bg-gray-800 dark:text-gray-300">0</div>
|
||||
<h2 className="mt-4 text-lg font-semibold text-gray-900 dark:text-white">暂无待评价</h2>
|
||||
<p className="mt-2 text-sm text-gray-500 dark:text-gray-400">新的考核调研会出现在这里。</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
|
||||
{items.map((item) => (
|
||||
<div key={item.assignmentId} className="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-700 dark:bg-gray-800">
|
||||
<div key={item.assignmentId} className="rounded-[24px] border border-gray-200 bg-white p-5 shadow-[0_14px_36px_rgba(15,23,42,0.07)] dark:border-gray-700 dark:bg-gray-900 sm:rounded-lg sm:shadow-none">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<h2 className="text-base font-semibold text-gray-900 dark:text-white">{item.title}</h2>
|
||||
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">{item.targetName}</p>
|
||||
<div className="min-w-0">
|
||||
<div className="mb-2 text-xs font-semibold text-blue-600 dark:text-blue-300">待填写</div>
|
||||
<h2 className="text-xl font-semibold leading-snug text-gray-950 dark:text-white sm:text-base">{item.title}</h2>
|
||||
<p className="mt-2 truncate text-sm text-gray-500 dark:text-gray-400">评价对象:{item.targetName}</p>
|
||||
</div>
|
||||
<StatusBadge status={item.status} />
|
||||
</div>
|
||||
<div className="mt-4 flex items-center justify-between text-sm">
|
||||
<div className="mt-5 flex items-center justify-between gap-3 text-sm">
|
||||
<span className="text-gray-500 dark:text-gray-400">{item.dueAt ? `截止 ${formatDate(item.dueAt)}` : '无截止时间'}</span>
|
||||
<Link
|
||||
href={`/performance-survey/survey/${item.surveyId}?targetId=${item.targetId}`}
|
||||
className="rounded-md bg-gray-900 px-3 py-1.5 text-white hover:bg-gray-700 dark:bg-white dark:text-gray-900"
|
||||
className="rounded-2xl bg-[#1677ff] px-5 py-2.5 font-semibold text-white shadow-[0_10px_22px_rgba(22,119,255,0.26)] hover:bg-[#0f66dd] dark:bg-white dark:text-gray-900"
|
||||
>
|
||||
填写
|
||||
去评价
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user