c2914c37e5
CI / verify (pull_request) Has been cancelled
Default new sub-accounts to store:create+store:manage, backfill empty permissions on /partner/me, and treat legacy store staff as allowed to mutate. Co-authored-by: Cursor <cursoragent@cursor.com>
107 lines
4.3 KiB
TypeScript
107 lines
4.3 KiB
TypeScript
import type { PartnerMe, PartnerPermissionKey } from '@dukang/shared-types';
|
|
|
|
export type PartnerNavKind = 'primary' | 'store_staff' | 'warehouse_staff';
|
|
|
|
export function isPrimaryAccount(account: PartnerMe | null | undefined): boolean {
|
|
return account?.isPrimary !== false;
|
|
}
|
|
|
|
export function isSubAccount(account: PartnerMe | null | undefined): boolean {
|
|
return !!account && account.isPrimary === false;
|
|
}
|
|
|
|
export function hasPartnerPermission(
|
|
account: PartnerMe | null | undefined,
|
|
permission: PartnerPermissionKey,
|
|
): boolean {
|
|
if (!account) return false;
|
|
if (isPrimaryAccount(account)) return true;
|
|
return account.permissions?.includes(permission) ?? false;
|
|
}
|
|
|
|
export function hasAnyPartnerPermission(
|
|
account: PartnerMe | null | undefined,
|
|
permissions: PartnerPermissionKey[],
|
|
): boolean {
|
|
return permissions.some((p) => hasPartnerPermission(account, p));
|
|
}
|
|
|
|
/** 与后端 GET /partner/dashboard 权限点一致 */
|
|
export function canAccessPartnerDashboard(account: PartnerMe | null | undefined): boolean {
|
|
return hasAnyPartnerPermission(account, [
|
|
'store:create',
|
|
'store:manage',
|
|
'order:view',
|
|
'warehouse:manage',
|
|
]);
|
|
}
|
|
|
|
/** 门店列表/拓店统计所需权限 */
|
|
export function canAccessPartnerStores(account: PartnerMe | null | undefined): boolean {
|
|
return hasAnyPartnerPermission(account, ['store:create', 'store:manage']);
|
|
}
|
|
|
|
/** 编辑资料 / 开闭店 / 重新上传:主账号、门店权限,或历史未配权限的门店类子账号 */
|
|
export function canManagePartnerStore(account: PartnerMe | null | undefined): boolean {
|
|
if (!account) return false;
|
|
if (isPrimaryAccount(account)) return true;
|
|
if (isWarehouseStaff(account)) return false;
|
|
if (hasAnyPartnerPermission(account, ['store:manage', 'store:create'])) return true;
|
|
// 合伙人端早期创建的子账号可能 permissions 为空,按门店员工放开
|
|
return !Array.isArray(account.permissions) || account.permissions.length === 0;
|
|
}
|
|
|
|
/** 录入新店 */
|
|
export function canCreatePartnerStore(account: PartnerMe | null | undefined): boolean {
|
|
if (!account) return false;
|
|
if (isPrimaryAccount(account)) return true;
|
|
if (isWarehouseStaff(account)) return false;
|
|
if (hasPartnerPermission(account, 'store:create')) return true;
|
|
return !Array.isArray(account.permissions) || account.permissions.length === 0;
|
|
}
|
|
|
|
/** 与后端 GET /partner/orders 权限点一致 */
|
|
export function canAccessPartnerOrders(account: PartnerMe | null | undefined): boolean {
|
|
return hasAnyPartnerPermission(account, ['order:view', 'warehouse:manage']);
|
|
}
|
|
|
|
/** 仓库管理员:warehouse:manage,或仅有 order:view(无门店权限) */
|
|
export function isWarehouseStaff(account: PartnerMe | null | undefined): boolean {
|
|
if (!account || isPrimaryAccount(account)) return false;
|
|
if (hasPartnerPermission(account, 'warehouse:manage')) return true;
|
|
const hasStore =
|
|
hasPartnerPermission(account, 'store:create') || hasPartnerPermission(account, 'store:manage');
|
|
if (hasPartnerPermission(account, 'order:view') && !hasStore) return true;
|
|
return false;
|
|
}
|
|
|
|
export function getPartnerNavKind(account: PartnerMe | null | undefined): PartnerNavKind {
|
|
if (!account || isPrimaryAccount(account)) return 'primary';
|
|
if (isWarehouseStaff(account)) return 'warehouse_staff';
|
|
return 'store_staff';
|
|
}
|
|
|
|
/** 是否已配置管仓:主账号看 hasWarehouseAccess;子账号还需有仓库相关权限 */
|
|
export function hasWarehouseAccess(account: PartnerMe | null | undefined): boolean {
|
|
if (!account) return false;
|
|
if (account.hasWarehouseAccess === false) return false;
|
|
if (account.hasWarehouseAccess === true) return true;
|
|
// 旧缓存无字段时保守:主账号未知视为无,避免误展示全城订单
|
|
return false;
|
|
}
|
|
|
|
export function partnerHomePath(account: PartnerMe | null | undefined): string {
|
|
return '/';
|
|
}
|
|
|
|
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;
|
|
const prefixes = navKind === 'warehouse_staff' ? WAREHOUSE_STAFF_PREFIXES : STORE_STAFF_PREFIXES;
|
|
return prefixes.some(
|
|
(prefix) => prefix !== '/login' && (pathname === prefix || pathname.startsWith(`${prefix}/`)),
|
|
);
|
|
}
|