account_balance
@@ -252,7 +247,7 @@ export default function HomePage() {
订单管理
)}
- {(isPrimary || isWarehouse) && (
+ {(isPrimary || isWarehouse) && warehouseOk && (
)}
+ {(isPrimary || isWarehouse) && !warehouseOk && (
+
+
+
warehouse
+
未配置仓库管理权限
+
+ 购酒订单由总部履约,不会推送到本账号。如需管仓发货,请联系总部配置仓库。
+
+
+
+ )}
+
{!isWarehouse && (
<>
diff --git a/apps/h5-partner/src/pages/OrderListPage.tsx b/apps/h5-partner/src/pages/OrderListPage.tsx
index c9e683a..bd7ce97 100644
--- a/apps/h5-partner/src/pages/OrderListPage.tsx
+++ b/apps/h5-partner/src/pages/OrderListPage.tsx
@@ -2,6 +2,8 @@ import { useEffect, useMemo, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import PageHeader from '@dukang/shared-ui/PageHeader';
import { isLoggedIn, request } from '../lib/api';
+import { usePartnerSession } from '../contexts/PartnerSessionContext';
+import { hasWarehouseAccess } from '../lib/partnerAccess';
type DateFilter = 'today' | '7d' | '30d';
type StatusFilter = 'ALL' | 'PENDING_SHIP' | 'SHIPPING' | 'COMPLETED' | 'ABNORMAL';
@@ -34,15 +36,24 @@ type OrderListPageProps = {
tabRoot?: boolean;
};
+type OrdersResponse = {
+ list: Array>;
+ hasWarehouseAccess?: boolean;
+ message?: string;
+};
+
export default function OrderListPage({ tabRoot = false }: OrderListPageProps) {
const navigate = useNavigate();
- const [data, setData] = useState<{ list: Array> }>({ list: [] });
+ const { account } = usePartnerSession();
+ const warehouseOk = hasWarehouseAccess(account);
+ const [data, setData] = useState({ list: [] });
const [tab, setTab] = useState<'orders' | 'coupons'>('orders');
const [dateFilter, setDateFilter] = useState('today');
const [statusFilter, setStatusFilter] = useState('ALL');
const [shippingId, setShippingId] = useState(null);
const [shipForm, setShipForm] = useState({ logisticsCompany: '', trackingNo: '', manualQueryUrl: '' });
const [shipModalId, setShipModalId] = useState(null);
+ const [loaded, setLoaded] = useState(false);
useEffect(() => {
document.title = '订单管理';
@@ -50,8 +61,22 @@ export default function OrderListPage({ tabRoot = false }: OrderListPageProps) {
useEffect(() => {
if (!isLoggedIn()) { navigate('/login'); return; }
- request<{ list: Array> }>('PARTNER_H5', '/partner/orders').then(setData);
- }, [navigate]);
+ if (!warehouseOk) {
+ setData({ list: [], hasWarehouseAccess: false, message: '未配置仓库管理权限' });
+ setLoaded(true);
+ return;
+ }
+ request('PARTNER_H5', '/partner/orders')
+ .then((res) => {
+ setData({
+ list: Array.isArray(res.list) ? res.list : [],
+ hasWarehouseAccess: res.hasWarehouseAccess,
+ message: res.message,
+ });
+ })
+ .catch(() => setData({ list: [] }))
+ .finally(() => setLoaded(true));
+ }, [navigate, warehouseOk]);
const filtered = useMemo(() => data.list.filter((o) => {
if (statusFilter === 'ALL') return true;
@@ -83,8 +108,12 @@ export default function OrderListPage({ tabRoot = false }: OrderListPageProps) {
body: JSON.stringify(shipForm),
});
setShipModalId(null);
- const next = await request<{ list: Array> }>('PARTNER_H5', '/partner/orders');
- setData(next);
+ const next = await request('PARTNER_H5', '/partner/orders');
+ setData({
+ list: Array.isArray(next.list) ? next.list : [],
+ hasWarehouseAccess: next.hasWarehouseAccess,
+ message: next.message,
+ });
} catch (err) {
window.alert(err instanceof Error ? err.message : '发货失败');
} finally {
@@ -97,6 +126,21 @@ export default function OrderListPage({ tabRoot = false }: OrderListPageProps) {
return s.includes('PENDING') || s === 'PAID' || s === 'PENDING_SHIP';
}
+ if (loaded && !warehouseOk) {
+ return (
+
+ {!tabRoot &&
navigate('/')} />}
+
+
warehouse
+
未配置仓库管理权限
+
+ 购酒订单由总部履约,不会推送到本账号。如需管仓发货,请联系总部配置仓库。
+
+
+
+ );
+ }
+
return (
{!tabRoot &&
navigate('/')} />}
diff --git a/apps/h5-partner/src/styles.css b/apps/h5-partner/src/styles.css
index de0138a..34d0b9c 100644
--- a/apps/h5-partner/src/styles.css
+++ b/apps/h5-partner/src/styles.css
@@ -3278,8 +3278,17 @@ body {
border-top: 1px dashed rgba(166, 29, 36, 0.15);
}
-.partner-home--flush-top .partner-home-body {
- padding-top: 20px;
+.partner-warehouse-denied {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ padding: 20px 12px;
+}
+
+.partner-warehouse-denied .material-symbols-outlined {
+ font-size: 36px;
+ font-variation-settings: 'FILL' 0;
}
.partner-home--flush-top.partner-store-page,
diff --git a/packages/shared-types/src/partner.ts b/packages/shared-types/src/partner.ts
index 30cc540..60a985e 100644
--- a/packages/shared-types/src/partner.ts
+++ b/packages/shared-types/src/partner.ts
@@ -17,6 +17,10 @@ export interface PartnerMe {
/** 子账号联系主账号用 */
primaryPhone?: string;
primaryName?: string;
+ /** 主账号绑定的管仓 ID(有则本城酒单推送至该仓) */
+ managedWarehouseId?: string | null;
+ /** 是否已配置仓库管理(无则不展示/不推送酒订单) */
+ hasWarehouseAccess?: boolean;
}
export interface UpdatePartnerMeRequest {
diff --git a/server/dukang-api/src/modules/city-scope/partner-city.service.ts b/server/dukang-api/src/modules/city-scope/partner-city.service.ts
index 461b6ca..69e94e4 100644
--- a/server/dukang-api/src/modules/city-scope/partner-city.service.ts
+++ b/server/dukang-api/src/modules/city-scope/partner-city.service.ts
@@ -103,10 +103,16 @@ export class PartnerCityService {
if (!primary.cityId) return { id: -1n };
const warehouseIds = await this.resolveManagedWarehouseIds(primary.id);
- if (warehouseIds.length > 0) {
- return { fulfillmentWarehouseId: { in: warehouseIds } };
+ // 未配置管仓:不推送/不展示酒订单(同城无仓由总部履约)
+ if (warehouseIds.length === 0) {
+ return { id: -1n };
}
- return { cityId: primary.cityId };
+ return { fulfillmentWarehouseId: { in: warehouseIds } };
+ }
+
+ async hasManagedWarehouse(partnerAccountId: bigint): Promise {
+ const ids = await this.resolveManagedWarehouseIds(partnerAccountId);
+ return ids.length > 0;
}
/** 合伙人可管仓库:主账号 managedWarehouseId + 绑定为管仓合伙人的仓 */
diff --git a/server/dukang-api/src/modules/settlement/settlement.controller.ts b/server/dukang-api/src/modules/settlement/settlement.controller.ts
index 4117757..011d715 100644
--- a/server/dukang-api/src/modules/settlement/settlement.controller.ts
+++ b/server/dukang-api/src/modules/settlement/settlement.controller.ts
@@ -9,6 +9,7 @@ import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
import { PrismaService } from '../../common/prisma/prisma.module';
+import { PartnerCityService } from '../city-scope/partner-city.service';
class UpdatePartnerMeDto {
@IsOptional()
@@ -243,7 +244,10 @@ export class AdminWineryBillController {
@Controller('partner/me')
@UseGuards(JwtAuthGuard)
export class PartnerMeController {
- constructor(private readonly prisma: PrismaService) {}
+ constructor(
+ private readonly prisma: PrismaService,
+ private readonly partnerCityService: PartnerCityService,
+ ) {}
@Get()
async me(@CurrentUser() user: AuthUser) {
@@ -274,6 +278,7 @@ export class PartnerMeController {
where: { id: account.parentAccountId },
});
}
+ const hasWarehouseAccess = await this.partnerCityService.hasManagedWarehouse(primary.id);
return {
id: account.id.toString(),
name: account.name,
@@ -288,6 +293,8 @@ export class PartnerMeController {
hasWechat: !!account.wxOpenId,
wxNickname: account.wxNickname ?? undefined,
wxAvatarUrl: account.wxAvatarUrl ?? undefined,
+ managedWarehouseId: primary.managedWarehouseId?.toString() ?? null,
+ hasWarehouseAccess,
};
}
}
diff --git a/server/dukang-api/src/modules/trade/trade.service.ts b/server/dukang-api/src/modules/trade/trade.service.ts
index 31be90d..ffcce37 100644
--- a/server/dukang-api/src/modules/trade/trade.service.ts
+++ b/server/dukang-api/src/modules/trade/trade.service.ts
@@ -509,6 +509,7 @@ export class TradeService {
async listPartnerOrders(partnerAccountId: bigint, page = 1, pageSize = 20) {
const primary = await this.partnerCityService.resolvePrimaryAccount(partnerAccountId);
+ const hasWarehouseAccess = await this.partnerCityService.hasManagedWarehouse(primary.id);
const where = await this.partnerCityService.buildPartnerOrderWhere(primary.id);
const [list, total] = await Promise.all([
this.prisma.order.findMany({
@@ -520,7 +521,14 @@ export class TradeService {
}),
this.prisma.order.count({ where }),
]);
- return { list: serializeBigInt(list.map(mapOrderCompat)), total, page, pageSize };
+ return {
+ list: serializeBigInt(list.map(mapOrderCompat)),
+ total,
+ page,
+ pageSize,
+ hasWarehouseAccess,
+ message: hasWarehouseAccess ? undefined : '未配置仓库管理权限,购酒订单由总部履约',
+ };
}
async getPartnerOrder(partnerAccountId: bigint, orderId: bigint) {