diff --git a/apps/admin-web/src/pages/OrdersPage.tsx b/apps/admin-web/src/pages/OrdersPage.tsx index dfdce64..750ef83 100644 --- a/apps/admin-web/src/pages/OrdersPage.tsx +++ b/apps/admin-web/src/pages/OrdersPage.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; +import { Link } from 'react-router-dom'; import { Alert, Button, @@ -175,6 +176,7 @@ export default function OrdersPage() { const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [batchDeleteOpen, setBatchDeleteOpen] = useState(false); const [batchDeleting, setBatchDeleting] = useState(false); + const [deletingId, setDeletingId] = useState(null); const [shipDefaults, setShipDefaults] = useState(null); const [shipping, setShipping] = useState(false); const [logisticsShipping, setLogisticsShipping] = useState(false); @@ -217,6 +219,7 @@ export default function OrdersPage() { const qs = new URLSearchParams({ page: String(page), pageSize: String(pageSize) }); if (values.orderNo) qs.set('orderNo', values.orderNo); if (values.status) qs.set('status', values.status); + if (values.orderType) qs.set('orderType', values.orderType); if (values.cityId) qs.set('cityId', values.cityId); if (values.receiverPhone) qs.set('receiverPhone', values.receiverPhone); if (values.fulfillmentHold) qs.set('fulfillmentHold', 'true'); @@ -389,6 +392,43 @@ export default function OrdersPage() { } } + function askDeleteOrder(id: string, orderNo?: string) { + Modal.confirm({ + title: '确认删除订单?', + content: ( +
+

将永久删除订单{orderNo ? ` ${orderNo}` : ''} 及其配送、权益券、核销、发票等关联数据。

+

此操作不可恢复,请确认不是真实线上订单。

+
+ ), + okText: '确认删除', + okType: 'danger', + cancelText: '取消', + onOk: () => deleteOrder(id), + }); + } + + async function deleteOrder(id: string) { + setDeletingId(id); + try { + const res = await request<{ deleted: number; message: string }>(`/admin/orders/${id}`, { + method: 'DELETE', + }); + message.success(res.message || '订单已删除'); + if (detail?.id === id) { + setDrawerOpen(false); + setDetail(null); + } + setSelectedRowKeys((prev) => prev.filter((k) => k !== id)); + void load(); + } catch (e) { + message.error(e instanceof Error ? e.message : '删除失败'); + throw e; + } finally { + setDeletingId(null); + } + } + const columns: ColumnsType = [ { title: '订单号', dataIndex: 'orderNo', width: 180 }, { @@ -455,7 +495,7 @@ export default function OrdersPage() { }, { title: '操作', - width: 140, + width: 180, fixed: 'right', render: (_, row) => ( @@ -467,6 +507,17 @@ export default function OrdersPage() { 配送 )} + {canDeleteOrders && ( + + )} ), }, @@ -493,6 +544,21 @@ export default function OrdersPage() { ) : null} + + {!canDeleteOrders && profile ? ( + + 非超管账号需在 权限分配 中勾选危险操作「删除订单」。 + + } + /> + ) : null} +
{ setPage(1); void load(); }}> @@ -500,6 +566,17 @@ export default function OrdersPage() { + } /> } /> } /> + } /> + } /> } /> } /> } /> diff --git a/apps/h5-partner/src/pages/CenterPage.tsx b/apps/h5-partner/src/pages/CenterPage.tsx index 26b49a0..317719c 100644 --- a/apps/h5-partner/src/pages/CenterPage.tsx +++ b/apps/h5-partner/src/pages/CenterPage.tsx @@ -219,6 +219,15 @@ export default function CenterPage({ variant = 'primary', roleLabel }: CenterPag chevron_right + +
+
+ receipt_long +
+ 代下单列表 +
+ chevron_right +
diff --git a/apps/h5-partner/src/pages/ProxyOrderDetailPage.tsx b/apps/h5-partner/src/pages/ProxyOrderDetailPage.tsx new file mode 100644 index 0000000..7de79c1 --- /dev/null +++ b/apps/h5-partner/src/pages/ProxyOrderDetailPage.tsx @@ -0,0 +1,117 @@ +import { useEffect, useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import PageHeader from '@dukang/shared-ui/PageHeader'; +import type { PartnerProxyOrderListItem } from '@dukang/shared-types'; +import { request } from '../lib/api'; + +function fmtMoney(n: number) { + return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); +} + +function fmtTime(value: string | undefined) { + if (!value) return '—'; + const d = new Date(value); + if (Number.isNaN(d.getTime())) return value; + const pad = (n: number) => String(n).padStart(2, '0'); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; +} + +function deliveryLabel(order: PartnerProxyOrderListItem) { + const t = String(order.deliveryType || '').toUpperCase(); + if (t === 'ON_SITE_PICKUP') return '现场提货'; + if (t === 'CROSS_CITY') return '跨城配送'; + if (t === 'LOCAL') return '同城配送'; + return '线下代下单'; +} + +export default function ProxyOrderDetailPage() { + const { id } = useParams(); + const navigate = useNavigate(); + const [order, setOrder] = useState(null); + const [error, setError] = useState(''); + + useEffect(() => { + document.title = '代下单详情'; + }, []); + + useEffect(() => { + if (!id) return; + void request('PARTNER_H5', `/partner/proxy-orders/${id}`) + .then(setOrder) + .catch((e) => setError(e instanceof Error ? e.message : '加载失败')); + }, [id]); + + const img = order?.imageResource?.url || ''; + + return ( +
+ navigate('/center/proxy-orders')} /> + + {error && ( +

+ {error} +

+ )} + + {!order && !error &&

加载中…

} + + {order && ( +
+
+
+ NO. {order.orderNo} + + 已完成 + +
+
+
+ {!img && liquor} +
+
+

{order.productName || '杜康好酒'}

+ {order.productSpec && ( +

+ {order.productSpec} +

+ )} +

+ ×{order.quantity} · ¥{fmtMoney(Number(order.payAmount || 0))} +

+

+ 权益 ¥{fmtMoney(Number(order.benefitAmount || 0))} +

+
+
+
+ +
+

客户信息

+

姓名:{order.receiverName || '—'}

+

手机:{order.receiverPhone || '—'}

+

+ 地址:{order.receiverAddress || (String(order.deliveryType).toUpperCase() === 'ON_SITE_PICKUP' ? '现场提货' : '—')} +

+
+ +
+

订单信息

+

配送方式:{deliveryLabel(order)}

+

下单时间:{fmtTime(order.createdAt)}

+

支付状态:已付款(线下)

+

订单状态:已完成并发放权益

+
+
+ )} +
+ ); +} diff --git a/apps/h5-partner/src/pages/ProxyOrderListPage.tsx b/apps/h5-partner/src/pages/ProxyOrderListPage.tsx new file mode 100644 index 0000000..0c7267a --- /dev/null +++ b/apps/h5-partner/src/pages/ProxyOrderListPage.tsx @@ -0,0 +1,142 @@ +import { useCallback, useEffect, useState, type FormEvent } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import PageHeader from '@dukang/shared-ui/PageHeader'; +import PullToRefresh from '@dukang/shared-ui/PullToRefresh'; +import type { PartnerProxyOrderListItem, PartnerProxyOrderListResponse } from '@dukang/shared-types'; +import { isLoggedIn, request } from '../lib/api'; + +function fmtMoney(n: number) { + return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); +} + +function fmtTime(value: string | undefined) { + if (!value) return '—'; + const d = new Date(value); + if (Number.isNaN(d.getTime())) return value; + const pad = (n: number) => String(n).padStart(2, '0'); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; +} + +function deliveryLabel(item: PartnerProxyOrderListItem) { + const t = String(item.deliveryType || '').toUpperCase(); + if (t === 'ON_SITE_PICKUP') return '现场提货'; + if (t === 'CROSS_CITY') return '跨城配送'; + if (t === 'LOCAL') return '同城配送'; + return '线下代下单'; +} + +function coverUrl(item: PartnerProxyOrderListItem) { + return item.imageResource?.url || ''; +} + +export default function ProxyOrderListPage() { + const navigate = useNavigate(); + const [list, setList] = useState([]); + const [total, setTotal] = useState(0); + const [keyword, setKeyword] = useState(''); + const [q, setQ] = useState(''); + const [loading, setLoading] = useState(true); + + const loadList = useCallback(() => { + if (!isLoggedIn()) { + navigate('/login'); + return Promise.resolve(); + } + setLoading(true); + const params = new URLSearchParams({ page: '1', pageSize: '50' }); + if (q.trim()) params.set('keyword', q.trim()); + return request('PARTNER_H5', `/partner/proxy-orders?${params}`) + .then((res) => { + setList(Array.isArray(res.list) ? res.list : []); + setTotal(Number(res.total) || 0); + }) + .catch(() => { + setList([]); + setTotal(0); + }) + .finally(() => setLoading(false)); + }, [navigate, q]); + + useEffect(() => { + document.title = '代下单列表'; + }, []); + + useEffect(() => { + void loadList(); + }, [loadList]); + + function submitSearch(e: FormEvent) { + e.preventDefault(); + setQ(keyword.trim()); + } + + return ( + + navigate('/center')} /> + +
+ + search + setKeyword(e.target.value)} + /> + +

+ {loading ? '加载中…' : `共 ${total} 笔代下单`} +

+
+ +
+ {!loading && list.length === 0 &&
暂无代下单记录
} + + {list.map((o) => { + const orderId = String(o.id); + const img = coverUrl(o); + return ( + +
+ NO. {o.orderNo} + + 已完成 + +
+
+
+ {!img && liquor} +
+
+

{o.productName || '杜康好酒'}

+

+ ×{o.quantity} · ¥{fmtMoney(Number(o.payAmount || 0))} +

+

+ {deliveryLabel(o)} · {fmtTime(o.createdAt)} +

+
+
+
+ person +

+ {o.receiverName || '客户'} + {o.receiverPhone ? ` · ${o.receiverPhone}` : ''} + {o.receiverAddress ? ` · ${o.receiverAddress}` : ''} +

+
+ + ); + })} +
+
+ ); +} diff --git a/apps/h5-partner/src/pages/ProxyOrderPage.tsx b/apps/h5-partner/src/pages/ProxyOrderPage.tsx index d6afe75..7c21075 100644 --- a/apps/h5-partner/src/pages/ProxyOrderPage.tsx +++ b/apps/h5-partner/src/pages/ProxyOrderPage.tsx @@ -188,7 +188,7 @@ export default function ProxyOrderPage() { }); toastSuccess(`代下单成功:${order.orderNo}`); clearProxyOrderDraft(); - navigate(`/orders/${order.id}`); + navigate(`/center/proxy-orders/${order.id}`); } catch (e) { setMsg(e instanceof Error ? e.message : '下单失败'); } finally { diff --git a/packages/shared-types/src/hq-permissions.ts b/packages/shared-types/src/hq-permissions.ts index 1856d29..d092923 100644 --- a/packages/shared-types/src/hq-permissions.ts +++ b/packages/shared-types/src/hq-permissions.ts @@ -36,7 +36,7 @@ export const HQ_PERMISSION_CATALOG = [ export type HqPermissionKey = (typeof HQ_PERMISSION_CATALOG)[number]['key']; -/** 危险操作:角色默认与超管自动权限均不含,需在权限分配中显式勾选 */ +/** 危险操作:非超管角色默认不含,需在权限分配中显式勾选;超管默认拥有 */ export const HQ_DANGEROUS_PERMISSION_KEYS = [ 'users_delete', 'orders_delete', diff --git a/packages/shared-types/src/trade.ts b/packages/shared-types/src/trade.ts index 99da032..1aa2a4d 100644 --- a/packages/shared-types/src/trade.ts +++ b/packages/shared-types/src/trade.ts @@ -110,6 +110,23 @@ export type PartnerProxyOrderCreateRequest = { promoCodeId?: string; }; +/** 合伙人代下单列表项(与 OrderDto 兼容,附带收货信息) */ +export type PartnerProxyOrderListItem = OrderDto & { + receiverName?: string | null; + receiverPhone?: string | null; + receiverAddress?: string | null; + deliveryType?: string | null; + productSpec?: string | null; + imageResource?: { url?: string } | null; +}; + +export type PartnerProxyOrderListResponse = { + list: PartnerProxyOrderListItem[]; + total: number; + page: number; + pageSize: number; +}; + /** 总部代下单(线下完成发权益,无需短信验证) */ export type HqProxyOrderCreateRequest = { phone: string; diff --git a/server/dukang-api/src/common/guards/hq-permission.guard.ts b/server/dukang-api/src/common/guards/hq-permission.guard.ts index 846d381..11ec0f9 100644 --- a/server/dukang-api/src/common/guards/hq-permission.guard.ts +++ b/server/dukang-api/src/common/guards/hq-permission.guard.ts @@ -7,6 +7,7 @@ import { } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { + HQ_DANGEROUS_PERMISSION_KEYS, HQ_ROLE_DEFAULT_PERMISSIONS, expandHqPermissionKeys, hasAnySystemSettingsPermission, @@ -43,8 +44,12 @@ export class HqPermissionsResolver { const userKeys = userRows.map((r) => r.permissionKey); if (account.adminRole === 'SUPER_ADMIN') { - // 超管默认拥有业务/管理权限,但不含危险操作;危险权限需按用户显式勾选 - return expandHqPermissionKeys([...hqBasePermissionKeys(), ...userKeys]); + // 超管含危险操作(删用户/订单/城市);其他角色仍需在权限分配中显式勾选 + return expandHqPermissionKeys([ + ...hqBasePermissionKeys(), + ...HQ_DANGEROUS_PERMISSION_KEYS, + ...userKeys, + ]); } const roleRows = await this.prisma.hqRolePermission.findMany({ diff --git a/server/dukang-api/src/common/hq-operation/hq-operation.constants.ts b/server/dukang-api/src/common/hq-operation/hq-operation.constants.ts index c59cdce..02bf092 100644 --- a/server/dukang-api/src/common/hq-operation/hq-operation.constants.ts +++ b/server/dukang-api/src/common/hq-operation/hq-operation.constants.ts @@ -22,6 +22,7 @@ export const HqOperationAction = { ORDER_SHIP: 'ORDER_SHIP', ORDER_STATUS_DEBUG: 'ORDER_STATUS_DEBUG', ORDER_BATCH_DELETE: 'ORDER_BATCH_DELETE', + ORDER_DELETE: 'ORDER_DELETE', ORDER_PROXY_CREATE: 'ORDER_PROXY_CREATE', STORE_CREATE: 'STORE_CREATE', STORE_UPDATE: 'STORE_UPDATE', @@ -123,6 +124,7 @@ export const HQ_OPERATION_ACTION_LABELS: Record = { [HqOperationAction.ORDER_SHIP]: '订单发货', [HqOperationAction.ORDER_STATUS_DEBUG]: '订单状态调试', [HqOperationAction.ORDER_BATCH_DELETE]: '批量删除订单', + [HqOperationAction.ORDER_DELETE]: '删除订单', [HqOperationAction.ORDER_PROXY_CREATE]: '总部代下单', [HqOperationAction.STORE_CREATE]: '新增门店', [HqOperationAction.STORE_UPDATE]: '编辑门店', diff --git a/server/dukang-api/src/modules/ops/admin-hq-permissions.service.ts b/server/dukang-api/src/modules/ops/admin-hq-permissions.service.ts index d574809..01522cf 100644 --- a/server/dukang-api/src/modules/ops/admin-hq-permissions.service.ts +++ b/server/dukang-api/src/modules/ops/admin-hq-permissions.service.ts @@ -1,5 +1,6 @@ import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; import { + HQ_DANGEROUS_PERMISSION_KEYS, HQ_PERMISSION_CATALOG, HQ_ROLE_DEFAULT_PERMISSIONS, LEGACY_SYSTEM_SETTINGS_KEY, @@ -82,7 +83,10 @@ export class AdminHqPermissionsService { const userPermissionKeys = expandHqPermissionKeys(userPerms.map((p) => p.permissionKey)); if (account.adminRole === 'SUPER_ADMIN') { - const rolePermissionKeys = hqBasePermissionKeys(); + const rolePermissionKeys = [ + ...hqBasePermissionKeys(), + ...HQ_DANGEROUS_PERMISSION_KEYS, + ] as HqPermissionKey[]; const effectivePermissionKeys = [ ...new Set([...rolePermissionKeys, ...userPermissionKeys]), ] as HqPermissionKey[]; diff --git a/server/dukang-api/src/modules/ops/admin-orders.controller.ts b/server/dukang-api/src/modules/ops/admin-orders.controller.ts index 0622ea3..cc8d729 100644 --- a/server/dukang-api/src/modules/ops/admin-orders.controller.ts +++ b/server/dukang-api/src/modules/ops/admin-orders.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Param, Post, Put, Query, UseGuards } from '@nestjs/common'; +import { Body, Controller, Delete, Get, Param, Post, Put, Query, UseGuards } from '@nestjs/common'; import { HqAuthGuard } from '../../common/guards/hq-auth.guard'; import { HqPermissionGuard, @@ -43,6 +43,18 @@ export class AdminOrdersController { return this.ordersService.detail(BigInt(id)); } + @Delete(':id') + @UseGuards(HqPermissionGuard) + @RequireHqPermissions('orders_delete') + @HqOperation({ + action: HqOperationAction.ORDER_DELETE, + refType: 'ORDER', + refIdParam: 'id', + }) + remove(@Param('id') id: string) { + return this.ordersService.deleteOrder(BigInt(id)); + } + /** HQ 发货:调用小飞侠创建运单并更新配送信息 */ @Post(':id/ship') @HqOperation({ diff --git a/server/dukang-api/src/modules/ops/admin-orders.service.ts b/server/dukang-api/src/modules/ops/admin-orders.service.ts index 27464a2..51cc7f1 100644 --- a/server/dukang-api/src/modules/ops/admin-orders.service.ts +++ b/server/dukang-api/src/modules/ops/admin-orders.service.ts @@ -31,6 +31,7 @@ export class AdminOrdersService { if (query.orderNo) where.orderNo = { contains: query.orderNo }; if (query.status) where.status = query.status as Prisma.EnumOrderStatusFilter['equals']; + if (query.orderType) where.orderType = query.orderType as Prisma.EnumOrderTypeFilter['equals']; if (query.userId) where.userId = BigInt(query.userId); if (query.cityId) where.cityId = BigInt(query.cityId); if (query.receiverPhone) where.receiverPhone = { contains: query.receiverPhone }; @@ -335,6 +336,25 @@ export class AdminOrdersService { }; } + async deleteOrder(id: bigint) { + const order = await this.prisma.order.findUnique({ + where: { id }, + select: { id: true, orderNo: true }, + }); + if (!order) throw new NotFoundException('订单不存在'); + + await this.prisma.$transaction(async (tx) => { + await this.deleteOrdersInTx(tx, [id]); + }); + + return { + ok: true, + deleted: 1, + orderNo: order.orderNo, + message: `订单 ${order.orderNo} 及关联业务数据已删除`, + }; + } + private async deleteOrdersInTx(tx: Prisma.TransactionClient, orderIds: bigint[]) { if (!orderIds.length) return; @@ -368,6 +388,10 @@ export class AdminOrdersService { await tx.benefitCoupon.deleteMany({ where: { id: { in: couponIds } } }); } + await tx.userInvoice.deleteMany({ where: { orderId: { in: orderIds } } }); + await tx.wineryBillItem.deleteMany({ where: { orderId: { in: orderIds } } }); + await tx.logisticsBillItem.deleteMany({ where: { orderId: { in: orderIds } } }); + await tx.order.updateMany({ where: { originOrderId: { in: orderIds } }, data: { originOrderId: null }, diff --git a/server/dukang-api/src/modules/ops/dto/admin-query.dto.ts b/server/dukang-api/src/modules/ops/dto/admin-query.dto.ts index ba87b74..88f2df9 100644 --- a/server/dukang-api/src/modules/ops/dto/admin-query.dto.ts +++ b/server/dukang-api/src/modules/ops/dto/admin-query.dto.ts @@ -48,6 +48,10 @@ export class AdminOrdersQueryDto extends PaginationQueryDto { @IsString() status?: string; + @IsOptional() + @IsIn(['NORMAL', 'PROXY']) + orderType?: string; + @IsOptional() @IsString() userId?: string; diff --git a/server/dukang-api/src/modules/trade/trade.controller.ts b/server/dukang-api/src/modules/trade/trade.controller.ts index 6e724ac..729edd1 100644 --- a/server/dukang-api/src/modules/trade/trade.controller.ts +++ b/server/dukang-api/src/modules/trade/trade.controller.ts @@ -208,6 +208,26 @@ export class PartnerProxyOrderController { return this.tradeService.getPartnerProxyOrderOptions(user.actorId); } + @Get() + list( + @CurrentUser() user: AuthUser, + @Query('page') page = '1', + @Query('pageSize') pageSize = '20', + @Query('keyword') keyword?: string, + ) { + return this.tradeService.listPartnerProxyOrders( + user.actorId, + Number(page), + Number(pageSize), + keyword, + ); + } + + @Get(':id') + detail(@CurrentUser() user: AuthUser, @Param('id') id: string) { + return this.tradeService.getPartnerProxyOrder(user.actorId, BigInt(id)); + } + @Post('preview') preview(@CurrentUser() user: AuthUser, @Body() dto: PartnerProxyOrderPreviewDto) { return this.tradeService.previewPartnerProxyOrderForPartner(user.actorId, dto); diff --git a/server/dukang-api/src/modules/trade/trade.service.ts b/server/dukang-api/src/modules/trade/trade.service.ts index bd3efb4..ee2b27d 100644 --- a/server/dukang-api/src/modules/trade/trade.service.ts +++ b/server/dukang-api/src/modules/trade/trade.service.ts @@ -1359,7 +1359,76 @@ export class TradeService { }, }); - return this.getPartnerOrder(partnerAccountId, order.id); + return serializeBigInt(mapOrderCompat(order)); + } + + /** 合伙人代下单列表:按 proxyPartnerAccountId 归属,与管仓订单无关 */ + async listPartnerProxyOrders( + partnerAccountId: bigint, + page = 1, + pageSize = 20, + keyword?: string, + ) { + const primary = await this.partnerCityService.resolvePrimaryAccount(partnerAccountId); + const kw = keyword?.trim(); + const where = { + orderType: 'PROXY' as const, + proxyPartnerAccountId: primary.id, + ...(kw + ? { + OR: [ + { orderNo: { contains: kw } }, + { receiverPhone: { contains: kw } }, + { receiverName: { contains: kw } }, + { productName: { contains: kw } }, + ], + } + : {}), + }; + const take = Math.min(Math.max(pageSize, 1), 50); + const skip = (Math.max(page, 1) - 1) * take; + const [list, total] = await Promise.all([ + this.prisma.order.findMany({ + where, + include: { + delivery: true, + imageResource: true, + user: { select: { phone: true, nickname: true } }, + }, + orderBy: { createdAt: 'desc' }, + skip, + take, + }), + this.prisma.order.count({ where }), + ]); + return { + list: serializeBigInt(list.map(mapOrderCompat)), + total, + page: Math.max(page, 1), + pageSize: take, + }; + } + + async getPartnerProxyOrder(partnerAccountId: bigint, orderId: bigint) { + const primary = await this.partnerCityService.resolvePrimaryAccount(partnerAccountId); + const order = await this.prisma.order.findFirst({ + where: { + id: orderId, + orderType: 'PROXY', + proxyPartnerAccountId: primary.id, + }, + include: { + delivery: true, + user: true, + imageResource: true, + }, + }); + if (!order) throw new NotFoundException('代下单不存在'); + const statusLogs = await this.prisma.commonEvent.findMany({ + where: orderStatusLogWhere(orderId), + orderBy: { createdAt: 'desc' }, + }); + return serializeBigInt(mapOrderCompat({ ...order, statusLogs: mapStatusLogCompat(statusLogs) })); } /** HQ 代下单:商品/推广码选项(运营侧可看白名单测试酒) */