feat(distribution): 独立分销前台商城多租户体系、货源与订单数据严格隔离

This commit is contained in:
yml2213
2026-09-07 17:18:14 +08:00
parent 550b42eb22
commit ecaf15417b
34 changed files with 2397 additions and 119 deletions
+30 -6
View File
@@ -319,9 +319,17 @@ export async function fetchPostRentalNotice() {
return data.data
}
export async function fetchOrders(page = 1, pageSize = 20) {
export async function fetchOrders(page = 1, pageSize = 20, distributionSiteCode?: string) {
const siteCode =
distributionSiteCode ||
(typeof window !== 'undefined' ? localStorage.getItem('hfb_site_code') : '') ||
undefined
const params: Record<string, unknown> = { page, page_size: pageSize }
if (siteCode) {
params.distribution_site_code = siteCode
}
const { data } = await apiClient.get<ApiResponse<PaginatedResult<UserOrderListItem>>>('/orders', {
params: { page, page_size: pageSize },
params,
})
return data.data
}
@@ -343,13 +351,29 @@ export async function fetchSellerHandoffs(
return data.data
}
export async function fetchOrder(id: string | number) {
const { data } = await apiClient.get<ApiResponse<Order>>(`/orders/${id}`)
export async function fetchOrder(id: string | number, distributionSiteCode?: string) {
const siteCode =
distributionSiteCode ||
(typeof window !== 'undefined' ? localStorage.getItem('hfb_site_code') : '') ||
undefined
const params: Record<string, unknown> = {}
if (siteCode) {
params.distribution_site_code = siteCode
}
const { data } = await apiClient.get<ApiResponse<Order>>(`/orders/${id}`, { params })
return data.data
}
export async function createOrder(listingId: number) {
const { data } = await apiClient.post<ApiResponse<Order>>('/orders', { listing_id: listingId })
export async function createOrder(listingId: number, distributionSiteCode?: string) {
const siteCode =
distributionSiteCode ||
(typeof window !== 'undefined' ? localStorage.getItem('hfb_site_code') : '') ||
undefined
const payload: { listing_id: number; distribution_site_code?: string } = { listing_id: listingId }
if (siteCode) {
payload.distribution_site_code = siteCode
}
const { data } = await apiClient.post<ApiResponse<Order>>('/orders', payload)
return data.data
}
@@ -23,6 +23,7 @@ import {
import { centToYuan, formatCent, formatMoney } from '@/shared/utils/money'
import { formatDateMinute } from '@/shared/utils/time'
import { formatListingNo } from '@/shared/utils/listingDisplay'
import { useDistributionSiteStore } from '@/stores/distributionSite'
type BizType = 'rental' | 'crash'
@@ -44,6 +45,7 @@ interface UnifiedOrderItem {
const router = useRouter()
const route = useRoute()
const siteStore = useDistributionSiteStore()
const loading = ref(false)
const rentalOrders = ref<UserOrderListItem[]>([])
const crashOrders = ref<MohongOrder[]>([])
@@ -143,10 +145,11 @@ function onStatusTabChange(name: string | number) {
async function loadOrders() {
loading.value = true
try {
const [rentalResult, crashResult] = await Promise.allSettled([
fetchOrders(rentalPage.value, rentalPageSize),
fetchMyMohongOrders({ page: 1, page_size: 50 }),
])
const rentalPromise = fetchOrders(rentalPage.value, rentalPageSize)
const crashPromise = !siteStore.isDistribution
? fetchMyMohongOrders({ page: 1, page_size: 50 })
: Promise.resolve(null)
const [rentalResult, crashResult] = await Promise.allSettled([rentalPromise, crashPromise])
if (rentalResult.status === 'fulfilled') {
rentalOrders.value = rentalResult.value?.items || []
@@ -157,14 +160,16 @@ async function loadOrders() {
showToast({ message: '租赁订单加载失败', icon: 'warning-o' })
}
if (crashResult.status === 'fulfilled') {
crashOrders.value = crashResult.value?.items || []
} else {
if (!siteStore.isDistribution && crashResult.status === 'fulfilled' && crashResult.value) {
crashOrders.value = crashResult.value.items || []
} else if (!siteStore.isDistribution && crashResult.status === 'rejected') {
crashOrders.value = []
showToast({
message: readError(crashResult.reason, '撞车订单加载失败'),
icon: 'warning-o',
})
} else {
crashOrders.value = []
}
} finally {
loading.value = false
@@ -278,10 +283,20 @@ async function copyListingCode(order: UserOrderListItem) {
<button class="back-btn" @click="router.back()">
<van-icon name="arrow-left" :size="20" />
</button>
<h1>我的订单</h1>
<div class="header-title-wrap">
<h1>我的订单</h1>
<span v-if="siteStore.isDistribution" class="m-site-order-tag">
{{ siteStore.siteName }}
</span>
</div>
<span class="header-spacer"></span>
</header>
<div v-if="siteStore.isDistribution" class="site-order-notice-bar">
<van-icon name="shop-o" class="notice-icon" />
<span>当前仅展示【{{ siteStore.siteName }}】专属订单</span>
</div>
<van-tabs
v-model:active="activeTab"
class="custom-tabs"
@@ -471,7 +486,6 @@ async function copyListingCode(order: UserOrderListItem) {
}
.page-header h1 {
flex: 1;
margin: 0;
font-size: 17px;
font-weight: 700;
@@ -479,6 +493,47 @@ async function copyListingCode(order: UserOrderListItem) {
color: #111827;
}
.header-title-wrap {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
min-width: 0;
}
.m-site-order-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 999px;
background: rgba(20, 119, 255, 0.1);
border: 1px solid rgba(20, 119, 255, 0.25);
color: #1477ff;
font-size: 11px;
font-weight: 600;
max-width: 110px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.site-order-notice-bar {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
background: linear-gradient(90deg, #eff6ff, #f0fdf4);
border-bottom: 1px solid #dbeafe;
font-size: 12px;
color: #1d4ed8;
font-weight: 500;
}
.site-order-notice-bar .notice-icon {
font-size: 14px;
color: #2563eb;
}
.back-btn {
display: grid;
width: 36px;
@@ -1,3 +1,22 @@
.header-title-row {
display: flex;
align-items: center;
gap: 12px;
}
.site-order-tag {
display: inline-flex;
align-items: center;
padding: 4px 12px;
border-radius: 999px;
background: linear-gradient(135deg, rgba(20, 119, 255, 0.08), rgba(0, 198, 251, 0.12));
border: 1px solid rgba(20, 119, 255, 0.25);
color: #1477ff;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.2px;
}
.orders-toolbar {
margin-top: 24px;
display: flex;
@@ -15,6 +15,7 @@ import { centToYuan, formatCent, formatMoney } from '@/shared/utils/money'
import { orderStatusLabel } from '@/shared/utils/statusLabels'
import { formatDateTime } from '@/shared/utils/time'
import { formatListingNo } from '@/shared/utils/listingDisplay'
import { useDistributionSiteStore } from '@/stores/distributionSite'
type BizType = 'rental' | 'crash'
@@ -42,6 +43,7 @@ const route = useRoute()
const router = useRouter()
const searchKeyword = ref('')
const fallbackPendingPaymentMinutes = 15
const siteStore = useDistributionSiteStore()
const rentalTotal = ref(0)
const rentalPage = ref(1)
const rentalPageSize = 20
@@ -151,10 +153,11 @@ function handleTabChange(tab: string | number) {
async function loadOrders() {
loading.value = true
try {
const [rentalResult, crashResult] = await Promise.allSettled([
fetchOrders(rentalPage.value, rentalPageSize),
fetchMyMohongOrders({ page: 1, page_size: 50 }),
])
const rentalPromise = fetchOrders(rentalPage.value, rentalPageSize)
const crashPromise = !siteStore.isDistribution
? fetchMyMohongOrders({ page: 1, page_size: 50 })
: Promise.resolve(null)
const [rentalResult, crashResult] = await Promise.allSettled([rentalPromise, crashPromise])
if (rentalResult.status === 'fulfilled') {
rentalOrders.value = rentalResult.value?.items || []
@@ -165,11 +168,13 @@ async function loadOrders() {
ElMessage.error('租赁订单加载失败')
}
if (crashResult.status === 'fulfilled') {
crashOrders.value = crashResult.value?.items || []
} else {
if (!siteStore.isDistribution && crashResult.status === 'fulfilled' && crashResult.value) {
crashOrders.value = crashResult.value.items || []
} else if (!siteStore.isDistribution && crashResult.status === 'rejected') {
crashOrders.value = []
ElMessage.error(readError(crashResult.reason, '撞车订单加载失败'))
} else {
crashOrders.value = []
}
} finally {
loading.value = false
@@ -298,9 +303,17 @@ function bizTypeLabel(bizType: BizType) {
<template>
<section class="page">
<div class="page-header">
<p class="eyebrow">ORDERS</p>
<h1>我的订单</h1>
<p>租赁与撞车订单统一展示,按创建时间倒序排列。</p>
<p class="eyebrow">{{ siteStore.isDistribution ? 'DISTRIBUTION ORDERS' : 'ORDERS' }}</p>
<div class="header-title-row">
<h1>我的订单</h1>
<span v-if="siteStore.isDistribution" class="site-order-tag">
{{ siteStore.siteName }} · 专属订单
</span>
</div>
<p v-if="siteStore.isDistribution">
当前为【{{ siteStore.siteName }}】专属分销商城,仅展示在此分销站产生的订单记录。
</p>
<p v-else>租赁与撞车订单统一展示,按创建时间倒序排列。</p>
</div>
<div class="orders-toolbar">