feat(distribution): 独立分销前台商城多租户体系、货源与订单数据严格隔离
This commit is contained in:
@@ -244,3 +244,16 @@ export async function fetchDistributionSettlementItems(batchId: number) {
|
||||
)
|
||||
return data.data.items ?? []
|
||||
}
|
||||
|
||||
export interface SyncSiteAccountsResult {
|
||||
synced_count: number
|
||||
skipped_count: number
|
||||
total_active: number
|
||||
}
|
||||
|
||||
export async function syncDistributionSiteAccounts(siteId: number) {
|
||||
const { data } = await apiClient.post<ApiResponse<SyncSiteAccountsResult>>(
|
||||
`/admin/distribution/sites/${siteId}/sync-accounts`
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||
import { Plus, Shop, Link, DocumentCopy } from '@element-plus/icons-vue'
|
||||
import { Plus, Shop, Link, DocumentCopy, Refresh } from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchDistributionSites,
|
||||
onboardDistributionSite,
|
||||
syncDistributionSiteAccounts,
|
||||
type DistributionSite,
|
||||
type OnboardDistributionSitePayload,
|
||||
type OnboardDistributionSiteResult,
|
||||
@@ -126,6 +127,22 @@ function openDistributionAdmin() {
|
||||
window.open(`http://${window.location.hostname}:5190`, '_blank')
|
||||
}
|
||||
|
||||
const syncingSiteId = ref<number | null>(null)
|
||||
|
||||
async function handleSyncAccounts(row: DistributionSite) {
|
||||
syncingSiteId.value = row.id
|
||||
try {
|
||||
const res = await syncDistributionSiteAccounts(row.id)
|
||||
ElMessage.success(
|
||||
`同步成功!为【${row.site_name}】新增可售账号 ${res.synced_count} 个,已存在 ${res.skipped_count} 个(主站当前可上架总数 ${res.total_active})`
|
||||
)
|
||||
} catch (err) {
|
||||
ElMessage.error(readError(err, '同步商品失败'))
|
||||
} finally {
|
||||
syncingSiteId.value = null
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadSites()
|
||||
})
|
||||
@@ -191,6 +208,19 @@ onMounted(() => {
|
||||
{{ formatDateTime(row.created_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="140" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
:icon="Refresh"
|
||||
:loading="syncingSiteId === row.id"
|
||||
@click="handleSyncAccounts(row)"
|
||||
>
|
||||
同步商品
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ export interface PublicListingQuery {
|
||||
max_daily_loss?: number
|
||||
min_secret_kd?: number
|
||||
max_secret_kd?: number
|
||||
distribution_site_code?: string
|
||||
[key: `resource_${string}_min`]: number | undefined
|
||||
[key: `resource_${string}_max`]: number | undefined
|
||||
}
|
||||
@@ -124,8 +125,13 @@ export async function fetchListings(query: PublicListingQuery = {}) {
|
||||
}
|
||||
|
||||
export async function fetchListingsPage(query: PublicListingQuery = {}) {
|
||||
const siteCode =
|
||||
query.distribution_site_code ||
|
||||
(typeof window !== 'undefined' ? localStorage.getItem('hfb_site_code') : '') ||
|
||||
undefined
|
||||
const effectiveQuery = siteCode ? { distribution_site_code: siteCode, ...query } : query
|
||||
const params = Object.fromEntries(
|
||||
Object.entries(query).filter(
|
||||
Object.entries(effectiveQuery).filter(
|
||||
([, value]) => value !== '' && value !== undefined && value !== null
|
||||
)
|
||||
)
|
||||
|
||||
@@ -40,8 +40,20 @@ import HomeStats from '../components/HomeStats.vue'
|
||||
import HomeFilters from '../components/HomeFilters.vue'
|
||||
import HomeZones from '../components/HomeZones.vue'
|
||||
import ListingCard from '../components/ListingCard.vue'
|
||||
import { useDistributionSiteStore } from '@/stores/distributionSite'
|
||||
|
||||
const siteStore = useDistributionSiteStore()
|
||||
|
||||
const announcements = ref<string[]>(defaultHomeAnnouncements)
|
||||
const displayAnnouncements = computed(() => {
|
||||
if (siteStore.isDistribution) {
|
||||
return [
|
||||
`【${siteStore.siteName}】官方认证独立分销站:账号实时同步主站,官方质检,安全秒交接!`,
|
||||
...announcements.value,
|
||||
]
|
||||
}
|
||||
return announcements.value
|
||||
})
|
||||
const banners = ref<HomeBannerSlide[]>(defaultHomeBanners)
|
||||
const awRecycle = ref<AWRecycleConfig>({ ...defaultAWRecycleConfig })
|
||||
const awRecycleDialogVisible = ref(false)
|
||||
@@ -354,9 +366,46 @@ loadHome()
|
||||
|
||||
<template>
|
||||
<section class="pc-home-redesign">
|
||||
<HomeAnnouncement :announcements="announcements" />
|
||||
<HomeAnnouncement :announcements="displayAnnouncements" />
|
||||
|
||||
<main class="home-content">
|
||||
<!-- 分销站专属标识 Banner -->
|
||||
<div v-if="siteStore.isDistribution" class="dist-portal-banner">
|
||||
<div class="dist-portal-content">
|
||||
<div class="dist-portal-tag">
|
||||
<span class="dist-pulse"></span>
|
||||
官方分销认证
|
||||
</div>
|
||||
<h2 class="dist-portal-title">{{ siteStore.siteName }} 专区</h2>
|
||||
<p class="dist-portal-desc">
|
||||
全站上架账号均由平台统一质检与自动交付,订单数据独立隔离,为您提供安全无忧的租号体验。
|
||||
</p>
|
||||
</div>
|
||||
<div class="dist-portal-badges">
|
||||
<div class="dist-badge-item">
|
||||
<span class="badge-icon">🛡️</span>
|
||||
<div class="badge-text">
|
||||
<strong>官方质检</strong>
|
||||
<small>账号状态实时同步</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dist-badge-item">
|
||||
<span class="badge-icon">⚡</span>
|
||||
<div class="badge-text">
|
||||
<strong>极速交付</strong>
|
||||
<small>自动交接 快速上号</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dist-badge-item">
|
||||
<span class="badge-icon">📑</span>
|
||||
<div class="badge-text">
|
||||
<strong>独立账单</strong>
|
||||
<small>专属订单 隐私隔离</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-section">
|
||||
<HomeBanner :banners="banners" />
|
||||
<HomeStats :stats="statCards" />
|
||||
@@ -367,7 +416,7 @@ loadHome()
|
||||
<strong>租号大厅</strong>
|
||||
<small>高哈夫币 · 安全交接 · 随租随玩</small>
|
||||
</RouterLink>
|
||||
<RouterLink class="biz-entry crash" to="/crash">
|
||||
<RouterLink v-if="!siteStore.isDistribution" class="biz-entry crash" to="/crash">
|
||||
<strong>撞车 <em>NEW</em></strong>
|
||||
<small>选购商品 · 支付后进群联系客服</small>
|
||||
</RouterLink>
|
||||
@@ -697,4 +746,112 @@ loadHome()
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dist-portal-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding: 24px 32px;
|
||||
border-radius: 20px;
|
||||
background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.12);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.dist-portal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.dist-portal-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
width: fit-content;
|
||||
padding: 3px 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(20, 119, 255, 0.2);
|
||||
border: 1px solid rgba(20, 119, 255, 0.4);
|
||||
color: #60a5fa;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.dist-pulse {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #38bdf8;
|
||||
box-shadow: 0 0 8px #38bdf8;
|
||||
}
|
||||
|
||||
.dist-portal-title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
color: #f8fafc;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
.dist-portal-desc {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.dist-portal-badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.dist-badge-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 12px 18px;
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.badge-icon {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.badge-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.badge-text strong {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #f1f5f9;
|
||||
}
|
||||
|
||||
.badge-text small {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.dist-portal-banner {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.dist-portal-badges {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -60,11 +60,30 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mobile-brand-title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.mobile-brand strong {
|
||||
color: #0f172a;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.mobile-brand-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 1px 5px;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
color: #ff6a00;
|
||||
background: rgba(255, 106, 0, 0.1);
|
||||
border: 1px solid rgba(255, 106, 0, 0.25);
|
||||
border-radius: 999px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.mobile-brand small {
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
@@ -212,6 +231,46 @@
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.mobile-dist-card {
|
||||
margin-bottom: 12px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
|
||||
.dist-card-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dist-card-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
background: rgba(20, 119, 255, 0.25);
|
||||
border: 1px solid rgba(20, 119, 255, 0.4);
|
||||
color: #60a5fa;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.dist-card-name {
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.dist-card-sub {
|
||||
margin: 6px 0 0;
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.banner-swipe {
|
||||
margin-bottom: 12px;
|
||||
border-radius: 8px;
|
||||
|
||||
@@ -55,11 +55,13 @@ import {
|
||||
hasGiftResources,
|
||||
} from '@/shared/utils/listingDisplay'
|
||||
import { buildMobileHomeListSignature, useMobileHomeCacheStore } from '@/stores/mobileHomeCache'
|
||||
import { useDistributionSiteStore } from '@/stores/distributionSite'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const session = useSessionStore()
|
||||
const siteStore = useDistributionSiteStore()
|
||||
const homeCache = useMobileHomeCacheStore()
|
||||
const scrollEl = ref<HTMLElement | null>(null)
|
||||
const loading = ref(false)
|
||||
@@ -80,6 +82,15 @@ const rangeFilters = ref<Record<string, { min: string; max: string }>>({})
|
||||
const refreshing = ref(false)
|
||||
const searchValue = ref('')
|
||||
const announcements = ref<string[]>(defaultHomeAnnouncements)
|
||||
const displayAnnouncements = computed(() => {
|
||||
if (siteStore.isDistribution) {
|
||||
return [
|
||||
`【${siteStore.siteName}】官方认证分销站,账号实时同步主站,售后有保障!`,
|
||||
...announcements.value,
|
||||
]
|
||||
}
|
||||
return announcements.value
|
||||
})
|
||||
const bannerSlides = ref<HomeBannerSlide[]>(defaultHomeBanners)
|
||||
const awRecycle = ref<AWRecycleConfig>({ ...defaultAWRecycleConfig })
|
||||
const awRecyclePreviewVisible = ref(false)
|
||||
@@ -797,10 +808,15 @@ syncMobileHomeQuery()
|
||||
<section class="mobile-hero">
|
||||
<div class="mobile-topbar">
|
||||
<div class="mobile-brand">
|
||||
<span class="mobile-logo">锤</span>
|
||||
<span class="mobile-logo">{{
|
||||
siteStore.isDistribution ? siteStore.siteName.slice(0, 1) : '锤'
|
||||
}}</span>
|
||||
<div>
|
||||
<strong>大锤商行</strong>
|
||||
<small>哈夫币租号</small>
|
||||
<div class="mobile-brand-title-row">
|
||||
<strong>{{ siteStore.siteName }}</strong>
|
||||
<span v-if="siteStore.isDistribution" class="mobile-brand-badge">官方分销</span>
|
||||
</div>
|
||||
<small>{{ siteStore.isDistribution ? '官方分销·平台保障' : '哈夫币租号' }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
@@ -844,7 +860,7 @@ syncMobileHomeQuery()
|
||||
:show-indicators="false"
|
||||
touchable
|
||||
>
|
||||
<van-swipe-item v-for="item in announcements" :key="item">
|
||||
<van-swipe-item v-for="item in displayAnnouncements" :key="item">
|
||||
<span>{{ item }}</span>
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
@@ -855,6 +871,15 @@ syncMobileHomeQuery()
|
||||
<!-- ========== Content 区域 ========== -->
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<section class="mobile-content">
|
||||
<!-- 分销站移动端专属认证卡片 -->
|
||||
<div v-if="siteStore.isDistribution" class="mobile-dist-card">
|
||||
<div class="dist-card-top">
|
||||
<span class="dist-card-badge">官方分销站</span>
|
||||
<strong class="dist-card-name">{{ siteStore.siteName }}</strong>
|
||||
</div>
|
||||
<p class="dist-card-sub">官方平台实时同步 · 统一质检交付 · 专属独立订单</p>
|
||||
</div>
|
||||
|
||||
<!-- Banner 轮播 -->
|
||||
<van-swipe class="banner-swipe" :autoplay="3600" lazy-render>
|
||||
<van-swipe-item v-for="slide in bannerSlides" :key="slide.title || slide.image_url">
|
||||
@@ -891,7 +916,7 @@ syncMobileHomeQuery()
|
||||
<strong>租号大厅</strong>
|
||||
<small>高哈夫币 · 随租随玩</small>
|
||||
</RouterLink>
|
||||
<RouterLink class="biz-entry" to="/crash">
|
||||
<RouterLink v-if="!siteStore.isDistribution" class="biz-entry" to="/crash">
|
||||
<strong>撞车</strong>
|
||||
<small>选购商品 · 一键找客服</small>
|
||||
<em class="biz-entry-badge">NEW</em>
|
||||
@@ -1082,7 +1107,7 @@ syncMobileHomeQuery()
|
||||
>湘ICP备2025146668号</a
|
||||
>
|
||||
<span class="home-footer-divider">|</span>
|
||||
<span class="home-footer-copyright">版权所有 ©2026 大锤网络游戏有限公司</span>
|
||||
<span class="home-footer-copyright">版权所有 ©2026 {{ siteStore.siteName }}</span>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user