import { useCallback, useEffect, useMemo, useState } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import type { PartnerLeaderboardEntry } from '@dukang/shared-types'; import PullToRefresh from '@dukang/shared-ui/PullToRefresh'; import { usePartnerPageView } from '../lib/usePageView'; import { isLoggedIn, request } from '../lib/api'; import { fetchPartnerLeaderboard } from '../lib/leaderboard'; import { canAccessPartnerDashboard, canAccessPartnerOrders, canAccessPartnerStores, getPartnerNavKind, hasWarehouseAccess, } from '../lib/partnerAccess'; import { usePartnerSession } from '../contexts/PartnerSessionContext'; function fmtMoney(n: number) { return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } const LEADERBOARD_PREVIEW_LIMIT = 3; function OrderSummarySection({ title, todayCount, pendingShip, shipping, completed, ordersLink = '/orders', }: { title?: string; todayCount: number; pendingShip: number; shipping: number; completed: number; ordersLink?: string; }) { return (

{title || `今日订单 ${todayCount}`}

查看全部 chevron_right

待发货

{pendingShip}

配送中

{shipping}

已完成

{completed}

); } function isPendingShip(status: string) { const s = status.toUpperCase(); return s.includes('PENDING') || s === 'PAID' || s === 'PENDING_SHIP'; } function isShipping(status: string) { const s = status.toUpperCase(); return s.includes('SHIP') || s === 'OUT_WAREHOUSE' || s === 'PENDING_RECEIVE'; } function isCompleted(status: string) { return status.toUpperCase() === 'COMPLETED'; } function isToday(dateStr: string) { const d = new Date(dateStr); const now = new Date(); return d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth() && d.getDate() === now.getDate(); } function summarizeOrders(orders: Array>) { let pendingShip = 0; let shipping = 0; let completed = 0; let todayCount = 0; for (const o of orders) { const status = String(o.status || ''); if (isToday(String(o.createdAt || ''))) todayCount += 1; if (isPendingShip(status)) pendingShip += 1; else if (isShipping(status)) shipping += 1; else if (isCompleted(status)) completed += 1; } return { pendingShip, shipping, completed, todayCount }; } function LeaderboardPreview({ entries }: { entries: PartnerLeaderboardEntry[] }) { return (

emoji_events 团队贡献榜

查看全部 chevron_right
{entries.length === 0 ? (

暂无排行数据

) : ( entries.map((entry) => (
person {entry.rank}

{entry.name} ({entry.roleLabel})

累计拓店: {entry.totalStores} 间

{entry.periodStores} 间

本月新增

)) )}
); } export default function HomePage() { usePartnerPageView('partner_home_view'); const navigate = useNavigate(); const { account } = usePartnerSession(); const navKind = getPartnerNavKind(account); const isPrimary = navKind === 'primary'; const isWarehouse = navKind === 'warehouse_staff'; const warehouseOk = hasWarehouseAccess(account); const canOrders = canAccessPartnerOrders(account) && warehouseOk && (isPrimary || isWarehouse); const canDashboard = canAccessPartnerDashboard(account) && !isWarehouse; const canStores = canAccessPartnerStores(account) && !isWarehouse; const [dash, setDash] = useState | null>(null); const [stores, setStores] = useState>>([]); const [orders, setOrders] = useState>>([]); const [leaderboardEntries, setLeaderboardEntries] = useState([]); useEffect(() => { document.title = '工作台'; }, []); const loadHome = useCallback(() => { if (!isLoggedIn()) { navigate('/login'); return Promise.resolve(); } if (!account) return Promise.resolve(); const tasks: Promise[] = []; if (canOrders) { tasks.push( request<{ list: Array> }>('PARTNER_H5', '/partner/orders', { silent: true }) .then((data) => setOrders(Array.isArray(data.list) ? data.list : [])) .catch(() => setOrders([])), ); } else { setOrders([]); } if (canDashboard) { tasks.push( request>('PARTNER_H5', '/partner/dashboard', { silent: true }) .then(setDash) .catch(() => setDash(null)), ); } else { setDash(null); } if (canStores) { tasks.push( request>>('PARTNER_H5', '/partner/stores', { silent: true }) .then((data) => setStores(Array.isArray(data) ? data : [])) .catch(() => setStores([])), ); } else { setStores([]); } tasks.push( fetchPartnerLeaderboard('month') .then((data) => { setLeaderboardEntries(data.list.slice(0, LEADERBOARD_PREVIEW_LIMIT)); }) .catch(() => { setLeaderboardEntries([]); }), ); return Promise.all(tasks).then(() => undefined); }, [navigate, account, canOrders, canDashboard, canStores]); useEffect(() => { void loadHome(); }, [loadHome]); const storeCount = Number(dash?.storeCount || stores.length || 0); const orderStats = useMemo(() => summarizeOrders(orders), [orders]); const pendingAuditCount = Number(dash?.pendingAuditCount || 0); const activeStores = stores.filter((s) => String(s.status).toUpperCase() === 'OPEN').length; const abnormalStores = Math.max(0, storeCount - activeStores); const monthNew = stores.filter((s) => { const created = new Date(String(s.createdAt || '')); const now = new Date(); return created.getMonth() === now.getMonth() && created.getFullYear() === now.getFullYear(); }).length; const lastMonthNew = stores.filter((s) => { const created = new Date(String(s.createdAt || '')); const now = new Date(); const last = new Date(now.getFullYear(), now.getMonth() - 1, 1); return created.getMonth() === last.getMonth() && created.getFullYear() === last.getFullYear(); }).length; const monthGrowthPct = lastMonthNew > 0 ? Math.round(((monthNew - lastMonthNew) / lastMonthNew) * 100) : (monthNew > 0 ? 100 : 0); const orderCount = Number(dash?.orderCount || orderStats.todayCount || 0); const revenue = orderCount * 128.45; const profit = revenue * 0.25; return (
{isPrimary && ( <>

实时营业额 (CNY) info

{fmtMoney(revenue)}

预计利润

¥ {fmtMoney(profit)}

shopping_cart_checkout
代下单
add_business
录入新店
account_balance
财务对账
monitoring
数据周报
)} {isWarehouse && (

订单管理

)} {canOrders && ( )} {(isPrimary || isWarehouse) && !warehouseOk && (
warehouse

未配置仓库管理权限

购酒订单由总部履约,不会推送到本账号。如需管仓发货,请联系总部配置仓库。

)} {canStores && ( <>

门店总数

{storeCount}

正常运营

{activeStores}

异常/闭店

{abnormalStores}

拓店情况

本月新增签约

{monthNew} {monthGrowthPct !== 0 && ( 0 ? ' partner-expansion-trend--up' : ' partner-expansion-trend--down'}`}> {monthGrowthPct > 0 ? 'trending_up' : 'trending_down'} {Math.abs(monthGrowthPct)}% )}

待审核门店

{pendingAuditCount}
)}
); }