feat(partner): let sub-accounts view team leaderboard
CI / verify (pull_request) Has been cancelled

Expose same-primary ranking on home/me for all staff including warehouse roles, and open the leaderboard API without business permission gates.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-17 10:02:42 +08:00
parent 972bdde650
commit 04253b9120
6 changed files with 26 additions and 14 deletions
+1 -1
View File
@@ -63,9 +63,9 @@ function SubAccountRoutes() {
<>
<Route path="/stores/new" element={<StoreCreatePage />} />
<Route path="/stores/:id" element={<StoreDetailPage />} />
<Route path="/leaderboard" element={<LeaderboardPage />} />
</>
)}
<Route path="/leaderboard" element={<LeaderboardPage />} />
{isWarehouse && <Route path="/orders/:id" element={<OrderDetailPage />} />}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
+2 -2
View File
@@ -48,8 +48,8 @@ export function partnerHomePath(account: PartnerMe | null | undefined): string {
return '/';
}
const STORE_STAFF_PREFIXES = ['/', '/stores', '/me', '/login'];
const WAREHOUSE_STAFF_PREFIXES = ['/', '/orders', '/me', '/login'];
const STORE_STAFF_PREFIXES = ['/', '/stores', '/me', '/leaderboard', '/login'];
const WAREHOUSE_STAFF_PREFIXES = ['/', '/orders', '/me', '/leaderboard', '/login'];
export function isSubAccountPath(pathname: string, navKind: PartnerNavKind = 'store_staff'): boolean {
if (pathname === '/login') return true;
+9
View File
@@ -251,6 +251,15 @@ export default function CenterPage({ variant = 'primary', roleLabel }: CenterPag
{!isPrimary && (
<section className="partner-menu-section">
<div className="partner-menu-card">
<Link to="/leaderboard" className="partner-menu-item">
<div className="partner-menu-item-left">
<div className="partner-menu-icon">
<span className="material-symbols-outlined">emoji_events</span>
</div>
<span className="body-md" style={{ fontSize: 16 }}></span>
</div>
<span className="material-symbols-outlined text-muted">chevron_right</span>
</Link>
<button type="button" className="partner-menu-item" onClick={() => { if (!contactSupport()) toastError('暂无客服电话'); }}>
<div className="partner-menu-item-left">
<div className="partner-menu-icon"><span className="material-symbols-outlined">support_agent</span></div>
+11 -10
View File
@@ -96,7 +96,7 @@ function LeaderboardPreview({ entries }: { entries: PartnerLeaderboardEntry[] })
<div className="partner-leaderboard-header">
<h3 className="headline-md" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<span className="material-symbols-outlined text-primary" style={{ fontSize: 20 }}>emoji_events</span>
</h3>
<Link to="/leaderboard" className="label-md text-primary" style={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<span className="material-symbols-outlined" style={{ fontSize: 14 }}>chevron_right</span>
@@ -158,16 +158,17 @@ export default function HomePage() {
if (!isWarehouse) {
request<Record<string, unknown>>('PARTNER_H5', '/partner/dashboard').then(setDash).catch(() => {});
request<Array<Record<string, unknown>>>('PARTNER_H5', '/partner/stores').then(setStores).catch(() => []);
fetchPartnerLeaderboard('month')
.then((data) => {
setLeaderboardEntries(data.list.slice(0, LEADERBOARD_PREVIEW_LIMIT));
})
.catch(() => {
setLeaderboardEntries([]);
});
} else {
request<Record<string, unknown>>('PARTNER_H5', '/partner/dashboard').then(setDash).catch(() => {});
}
// 主账号与全部子账号均可查看同团队贡献榜
fetchPartnerLeaderboard('month')
.then((data) => {
setLeaderboardEntries(data.list.slice(0, LEADERBOARD_PREVIEW_LIMIT));
})
.catch(() => {
setLeaderboardEntries([]);
});
}, [navigate, isWarehouse, isPrimary, warehouseOk]);
const storeCount = Number(dash?.storeCount || stores.length || 0);
@@ -317,10 +318,10 @@ export default function HomePage() {
</div>
</div>
</section>
<LeaderboardPreview entries={leaderboardEntries} />
</>
)}
<LeaderboardPreview entries={leaderboardEntries} />
</main>
</div>
);
@@ -47,7 +47,7 @@ export default function LeaderboardPage() {
return (
<div className="page-no-tab">
<PageHeader title="合伙人贡献榜" onBack={() => navigate('/')} />
<PageHeader title="团队贡献榜" onBack={() => navigate('/')} />
<div className="partner-leaderboard-tabs">
{PERIOD_TABS.map((tab) => (
@@ -89,6 +89,8 @@ export class PartnerDashboardController {
}
@Get('leaderboard')
/** 任意合伙人子账号可看同主账号排行(激励),不校验业务权限点 */
@RequirePartnerPermissions()
leaderboard(
@CurrentUser() user: AuthUser,
@Query('period') period?: string,