feat(distribution): 完善分销站与主站业务数据及权益风控隔离,修复历史商品归属
This commit is contained in:
@@ -103,7 +103,8 @@ func (h *Handler) ListMine(c *gin.Context) {
|
|||||||
response.Unauthorized(c, "缺少用户上下文")
|
response.Unauthorized(c, "缺少用户上下文")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
items, err := h.service.ListMine(c.Request.Context(), ownerID)
|
siteCode := strings.TrimSpace(c.GetHeader("X-Distribution-Site-Code"))
|
||||||
|
items, err := h.service.ListMine(c.Request.Context(), ownerID, siteCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeListingError(c, err)
|
writeListingError(c, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -170,12 +170,18 @@ func (r *Repository) FindAdmin(ctx context.Context, listingID uint64) (*ListingD
|
|||||||
return r.findDTO(ctx, "l.id = ?", listingID)
|
return r.findDTO(ctx, "l.id = ?", listingID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) ListMine(ctx context.Context, ownerID uint64) ([]ListingDTO, error) {
|
func (r *Repository) ListMine(ctx context.Context, ownerID uint64, siteCode ...string) ([]ListingDTO, error) {
|
||||||
var rows []listingRow
|
var rows []listingRow
|
||||||
err := r.baseQuery(ctx).
|
base := r.baseQuery(ctx).Where("l.owner_id = ?", ownerID)
|
||||||
Where("l.owner_id = ?", ownerID).
|
if len(siteCode) > 0 {
|
||||||
Order("l.id DESC").
|
code := strings.TrimSpace(siteCode[0])
|
||||||
Scan(&rows).Error
|
if code != "" {
|
||||||
|
base = base.Joins("INNER JOIN distribution_sites AS my_ds ON my_ds.id = l.distribution_site_id AND my_ds.site_code = ?", code)
|
||||||
|
} else {
|
||||||
|
base = base.Where("l.distribution_site_id IS NULL OR l.distribution_site_id = 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := base.Order("l.id DESC").Scan(&rows).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ func (s *Service) ListPublic(ctx context.Context, query PublicListQuery) (*Publi
|
|||||||
return s.repo.ListPublic(ctx, query)
|
return s.repo.ListPublic(ctx, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ListMine(ctx context.Context, ownerID uint64) ([]ListingDTO, error) {
|
func (s *Service) ListMine(ctx context.Context, ownerID uint64, siteCode ...string) ([]ListingDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
return s.repo.ListMine(ctx, ownerID)
|
return s.repo.ListMine(ctx, ownerID, siteCode...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) FindPublic(ctx context.Context, id uint64) (*ListingDTO, error) {
|
func (s *Service) FindPublic(ctx context.Context, id uint64) (*ListingDTO, error) {
|
||||||
|
|||||||
@@ -888,3 +888,63 @@ func TestCreateListingWithDistributionSiteCode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListMineSiteIsolation(t *testing.T) {
|
||||||
|
db := database.NewTestDB()
|
||||||
|
if err := database.MigrateListingLifecycleTestSchema(db); err != nil {
|
||||||
|
t.Fatalf("migrate err: %v", err)
|
||||||
|
}
|
||||||
|
repo := NewRepository(db, nil)
|
||||||
|
|
||||||
|
user := model.User{Phone: "18800000002", Nickname: "多站卖家", RealnameStatus: "verified", Status: "active"}
|
||||||
|
db.Create(&user)
|
||||||
|
|
||||||
|
site := model.DistributionSite{
|
||||||
|
SiteCode: "dist_x",
|
||||||
|
SiteName: "分销X",
|
||||||
|
Domain: "x.com",
|
||||||
|
Status: "active",
|
||||||
|
DisplayAccountEnabled: true,
|
||||||
|
}
|
||||||
|
db.Create(&site)
|
||||||
|
|
||||||
|
req1 := CreateRequest{Title: "主站商品", ServerRegion: "QQ", LoginPlatform: "PC", PriceCent: 1000}
|
||||||
|
l1, err := repo.Create(context.Background(), user.ID, req1, false, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Create main failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req2 := CreateRequest{Title: "分销商品", ServerRegion: "QQ", LoginPlatform: "PC", PriceCent: 2000}
|
||||||
|
l2, err := repo.Create(context.Background(), user.ID, req2, false, 0, "dist_x")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Create dist failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 分销站查询只返回分销站商品
|
||||||
|
distItems, err := repo.ListMine(context.Background(), user.ID, "dist_x")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ListMine dist_x err: %v", err)
|
||||||
|
}
|
||||||
|
if len(distItems) != 1 || distItems[0].ID != l2.ID {
|
||||||
|
t.Fatalf("expected only dist listing %d, got %v", l2.ID, distItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 主站查询只返回主站商品
|
||||||
|
mainItems, err := repo.ListMine(context.Background(), user.ID, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ListMine main err: %v", err)
|
||||||
|
}
|
||||||
|
if len(mainItems) != 1 || mainItems[0].ID != l1.ID {
|
||||||
|
t.Fatalf("expected only main listing %d, got %v", l1.ID, mainItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 不传站点时兼容返回全部
|
||||||
|
allItems, err := repo.ListMine(context.Background(), user.ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ListMine all err: %v", err)
|
||||||
|
}
|
||||||
|
if len(allItems) != 2 {
|
||||||
|
t.Fatalf("expected 2 listings, got %d", len(allItems))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,10 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che
|
|||||||
if err := appendCheckoutCompletedNotifications(tx, order, renterContent); err != nil {
|
if err := appendCheckoutCompletedNotifications(tx, order, renterContent); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := rentergrowth.AwardOrderCompleted(tx, order, settlement.PureCoinAmountCent, rentergrowth.SourceOrderCompleted); err != nil {
|
if order.DistributionSiteID == nil || *order.DistributionSiteID == 0 {
|
||||||
return nil, err
|
if err := rentergrowth.AwardOrderCompleted(tx, order, settlement.PureCoinAmountCent, rentergrowth.SourceOrderCompleted); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := saveFinalizedCheckout(tx, order, checkout, listing, account); err != nil {
|
if err := saveFinalizedCheckout(tx, order, checkout, listing, account); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ type SellerHandoffQuery struct {
|
|||||||
Page int
|
Page int
|
||||||
PageSize int
|
PageSize int
|
||||||
Status string
|
Status string
|
||||||
|
SiteCode string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SellerHandoffMetrics 为号主待办页提供跨分页的状态统计。
|
// SellerHandoffMetrics 为号主待办页提供跨分页的状态统计。
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func (h *Handler) List(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
page, pageSize := parsePagination(c)
|
page, pageSize := parsePagination(c)
|
||||||
siteCode := strings.TrimSpace(firstNonEmpty(c.Query("distribution_site_code"), c.Query("site_code")))
|
siteCode := strings.TrimSpace(firstNonEmpty(c.GetHeader("X-Distribution-Site-Code"), c.Query("distribution_site_code"), c.Query("site_code")))
|
||||||
items, err := h.service.ListForUser(c.Request.Context(), userID, page, pageSize, siteCode)
|
items, err := h.service.ListForUser(c.Request.Context(), userID, page, pageSize, siteCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeOrderError(c, err)
|
writeOrderError(c, err)
|
||||||
@@ -50,10 +50,12 @@ func (h *Handler) ListSellerHandoffs(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
page, pageSize := parsePagination(c)
|
page, pageSize := parsePagination(c)
|
||||||
|
siteCode := strings.TrimSpace(firstNonEmpty(c.GetHeader("X-Distribution-Site-Code"), c.Query("distribution_site_code"), c.Query("site_code")))
|
||||||
items, err := h.service.ListSellerHandoffs(c.Request.Context(), userID, SellerHandoffQuery{
|
items, err := h.service.ListSellerHandoffs(c.Request.Context(), userID, SellerHandoffQuery{
|
||||||
Page: page,
|
Page: page,
|
||||||
PageSize: pageSize,
|
PageSize: pageSize,
|
||||||
Status: c.Query("status"),
|
Status: c.Query("status"),
|
||||||
|
SiteCode: siteCode,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeOrderError(c, err)
|
writeOrderError(c, err)
|
||||||
@@ -72,7 +74,7 @@ func (h *Handler) Detail(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
siteCode := strings.TrimSpace(firstNonEmpty(c.Query("distribution_site_code"), c.Query("site_code")))
|
siteCode := strings.TrimSpace(firstNonEmpty(c.GetHeader("X-Distribution-Site-Code"), c.Query("distribution_site_code"), c.Query("site_code")))
|
||||||
item, err := h.service.FindForUser(c.Request.Context(), userID, id, siteCode)
|
item, err := h.service.FindForUser(c.Request.Context(), userID, id, siteCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeOrderError(c, err)
|
writeOrderError(c, err)
|
||||||
|
|||||||
@@ -63,9 +63,20 @@ func (r *Repository) Create(ctx context.Context, renterID uint64, req CreateRequ
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rentOriginalAmountCent := pricing.RentAmountCent
|
rentOriginalAmountCent := pricing.RentAmountCent
|
||||||
growthSnapshot, err := rentergrowth.SnapshotForUser(tx, renterID)
|
var growthSnapshot rentergrowth.DiscountSnapshot
|
||||||
if err != nil {
|
if distributionSite == nil {
|
||||||
return err
|
snap, err := rentergrowth.SnapshotForUser(tx, renterID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
growthSnapshot = snap
|
||||||
|
} else {
|
||||||
|
// 分销站点订单隔离主站成长等级免押与折扣,防止主站免押坏账与折扣侵蚀分销收益
|
||||||
|
growthSnapshot = rentergrowth.DiscountSnapshot{
|
||||||
|
LevelCode: rentergrowth.DefaultLevelCode,
|
||||||
|
LevelName: rentergrowth.DefaultLevelName,
|
||||||
|
DiscountBps: rentergrowth.DefaultDiscountBps,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rentDiscountAmountCent := rentergrowth.CalculateDiscountCent(pricing.PureCoinAmountCent, pricing.PureCoinPlatformFeeCent, growthSnapshot.DiscountBps)
|
rentDiscountAmountCent := rentergrowth.CalculateDiscountCent(pricing.PureCoinAmountCent, pricing.PureCoinPlatformFeeCent, growthSnapshot.DiscountBps)
|
||||||
if rentDiscountAmountCent > 0 {
|
if rentDiscountAmountCent > 0 {
|
||||||
|
|||||||
@@ -63,6 +63,11 @@ func (r *Repository) ListSellerHandoffs(ctx context.Context, userID uint64, quer
|
|||||||
if query.Status != "" {
|
if query.Status != "" {
|
||||||
base = base.Where("o.status = ?", query.Status)
|
base = base.Where("o.status = ?", query.Status)
|
||||||
}
|
}
|
||||||
|
if query.SiteCode != "" {
|
||||||
|
base = base.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", query.SiteCode)
|
||||||
|
} else {
|
||||||
|
base = base.Where("o.distribution_site_id IS NULL OR o.distribution_site_id = 0")
|
||||||
|
}
|
||||||
|
|
||||||
var total int64
|
var total int64
|
||||||
if err := base.Session(&gorm.Session{}).Count(&total).Error; err != nil {
|
if err := base.Session(&gorm.Session{}).Count(&total).Error; err != nil {
|
||||||
@@ -77,7 +82,7 @@ func (r *Repository) ListSellerHandoffs(ctx context.Context, userID uint64, quer
|
|||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
items = append(items, row.toUserListItem(userID, nil))
|
items = append(items, row.toUserListItem(userID, nil))
|
||||||
}
|
}
|
||||||
metrics, err := r.sellerHandoffMetrics(ctx, userID)
|
metrics, err := r.sellerHandoffMetrics(ctx, userID, query.SiteCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -90,16 +95,21 @@ func (r *Repository) ListSellerHandoffs(ctx context.Context, userID uint64, quer
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) sellerHandoffMetrics(ctx context.Context, userID uint64) (SellerHandoffMetrics, error) {
|
func (r *Repository) sellerHandoffMetrics(ctx context.Context, userID uint64, siteCode ...string) (SellerHandoffMetrics, error) {
|
||||||
base := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.owner_id = ?", userID)
|
base := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.owner_id = ?", userID)
|
||||||
|
if len(siteCode) > 0 && siteCode[0] != "" {
|
||||||
|
base = base.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", siteCode[0])
|
||||||
|
} else if len(siteCode) > 0 {
|
||||||
|
base = base.Where("o.distribution_site_id IS NULL OR o.distribution_site_id = 0")
|
||||||
|
}
|
||||||
var metrics SellerHandoffMetrics
|
var metrics SellerHandoffMetrics
|
||||||
if err := base.Where("o.status = ? AND o.handoff_status = ?", orderStatusPendingHandoff, handoffStatusPendingOwner).Count(&metrics.PendingHandoff).Error; err != nil {
|
if err := base.Session(&gorm.Session{}).Where("o.status = ? AND o.handoff_status = ?", orderStatusPendingHandoff, handoffStatusPendingOwner).Count(&metrics.PendingHandoff).Error; err != nil {
|
||||||
return SellerHandoffMetrics{}, err
|
return SellerHandoffMetrics{}, err
|
||||||
}
|
}
|
||||||
if err := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.owner_id = ? AND o.status = ?", userID, orderStatusPendingCheckoutConfirm).Count(&metrics.PendingCheckout).Error; err != nil {
|
if err := base.Session(&gorm.Session{}).Where("o.status = ?", orderStatusPendingCheckoutConfirm).Count(&metrics.PendingCheckout).Error; err != nil {
|
||||||
return SellerHandoffMetrics{}, err
|
return SellerHandoffMetrics{}, err
|
||||||
}
|
}
|
||||||
if err := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.owner_id = ? AND o.status IN ?", userID, sellerHandoffAbnormalStatuses()).Count(&metrics.Abnormal).Error; err != nil {
|
if err := base.Session(&gorm.Session{}).Where("o.status IN ?", sellerHandoffAbnormalStatuses()).Count(&metrics.Abnormal).Error; err != nil {
|
||||||
return SellerHandoffMetrics{}, err
|
return SellerHandoffMetrics{}, err
|
||||||
}
|
}
|
||||||
return metrics, nil
|
return metrics, nil
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-- +goose Up
|
||||||
|
|
||||||
|
-- 修复 000072 中误将展示货架 (distribution_site_accounts) 历史商品回填为分销站点来源的问题
|
||||||
|
-- 历史主站商品(在分销上传功能上线前创建的商品)来源应保持 distribution_site_id = NULL
|
||||||
|
UPDATE rental_listings l
|
||||||
|
JOIN distribution_site_accounts dsa ON dsa.listing_id = l.id
|
||||||
|
SET l.distribution_site_id = NULL
|
||||||
|
WHERE l.created_at < '2026-09-08 14:00:00';
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
SELECT 1;
|
||||||
@@ -135,6 +135,15 @@
|
|||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.growth-card.is-distribution > div {
|
||||||
|
background: #f0fdf4;
|
||||||
|
border-color: rgba(167, 243, 208, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.growth-card.is-distribution strong {
|
||||||
|
color: #059669;
|
||||||
|
}
|
||||||
|
|
||||||
/* ========== Balance Card ========== */
|
/* ========== Balance Card ========== */
|
||||||
.balance-card {
|
.balance-card {
|
||||||
margin: 12px 16px 14px;
|
margin: 12px 16px 14px;
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ import { uploadFile } from '@/shared/api/files'
|
|||||||
import { formatCent } from '@/shared/utils/money'
|
import { formatCent } from '@/shared/utils/money'
|
||||||
import { setPassword } from '@/features/auth/api/auth'
|
import { setPassword } from '@/features/auth/api/auth'
|
||||||
|
|
||||||
|
import { useDistributionSiteStore } from '@/stores/distributionSite'
|
||||||
|
|
||||||
const session = useSessionStore()
|
const session = useSessionStore()
|
||||||
|
const siteStore = useDistributionSiteStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const { unreadCount: notificationUnreadCount, unreadLabel: notificationUnreadLabel } =
|
const { unreadCount: notificationUnreadCount, unreadLabel: notificationUnreadLabel } =
|
||||||
@@ -353,7 +356,17 @@ function resolveAvatarURL(url: string | undefined | null) {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="growth-card">
|
<section v-if="siteStore.isDistribution" class="growth-card is-distribution">
|
||||||
|
<div>
|
||||||
|
<span>所属商城</span>
|
||||||
|
<strong>{{ siteStore.siteName || '专属分销商城' }}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>会员特权</span>
|
||||||
|
<strong>渠道直租专享</strong>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section v-else class="growth-card">
|
||||||
<div>
|
<div>
|
||||||
<span>租客成长等级</span>
|
<span>租客成长等级</span>
|
||||||
<strong>{{ session.renterGrowthLevelName }}</strong>
|
<strong>{{ session.renterGrowthLevelName }}</strong>
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
import type { PublicListingItem } from '@/features/listings/api/listings'
|
import type { PublicListingItem } from '@/features/listings/api/listings'
|
||||||
|
import { getEffectiveSiteCode } from '@/stores/distributionSite'
|
||||||
|
|
||||||
|
function getHistoryKey() {
|
||||||
|
const code = getEffectiveSiteCode()
|
||||||
|
return code ? `hfb.listing.view.history.${code}` : 'hfb.listing.view.history'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFavoriteKey() {
|
||||||
|
const code = getEffectiveSiteCode()
|
||||||
|
return code ? `hfb.listing.favorites.${code}` : 'hfb.listing.favorites'
|
||||||
|
}
|
||||||
|
|
||||||
const historyKey = 'hfb.listing.view.history'
|
|
||||||
const favoriteKey = 'hfb.listing.favorites'
|
|
||||||
const maxHistoryItems = 80
|
const maxHistoryItems = 80
|
||||||
|
|
||||||
export interface ListingCollectionItem {
|
export interface ListingCollectionItem {
|
||||||
@@ -12,10 +21,12 @@ export interface ListingCollectionItem {
|
|||||||
favorited_at?: string
|
favorited_at?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const historyItems = ref<ListingCollectionItem[]>(readItems(historyKey))
|
|
||||||
const favoriteItems = ref<ListingCollectionItem[]>(readItems(favoriteKey))
|
|
||||||
|
|
||||||
export function useListingCollections() {
|
export function useListingCollections() {
|
||||||
|
const historyKey = getHistoryKey()
|
||||||
|
const favoriteKey = getFavoriteKey()
|
||||||
|
const historyItems = ref<ListingCollectionItem[]>(readItems(historyKey))
|
||||||
|
const favoriteItems = ref<ListingCollectionItem[]>(readItems(favoriteKey))
|
||||||
|
|
||||||
const history = computed(() => historyItems.value)
|
const history = computed(() => historyItems.value)
|
||||||
const favorites = computed(() => favoriteItems.value)
|
const favorites = computed(() => favoriteItems.value)
|
||||||
const favoriteIDs = computed(() => new Set(favoriteItems.value.map(item => item.listing.id)))
|
const favoriteIDs = computed(() => new Set(favoriteItems.value.map(item => item.listing.id)))
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import { Refresh, Search } from '@element-plus/icons-vue'
|
import { Refresh, Search } from '@element-plus/icons-vue'
|
||||||
import { fetchSellerPickups, type SellerPickup } from '@/features/seller/api/sellerPickup'
|
import { fetchSellerPickups, type SellerPickup } from '@/features/seller/api/sellerPickup'
|
||||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||||
import { formatDateTime } from '@/shared/utils/time'
|
import { formatDateTime } from '@/shared/utils/time'
|
||||||
import { pickupStatusLabel } from '@/shared/utils/statusLabels'
|
import { pickupStatusLabel } from '@/shared/utils/statusLabels'
|
||||||
|
import { useDistributionSiteStore } from '@/stores/distributionSite'
|
||||||
|
|
||||||
|
const siteStore = useDistributionSiteStore()
|
||||||
|
const router = useRouter()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const items = ref<SellerPickup[]>([])
|
const items = ref<SellerPickup[]>([])
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const filters = reactive({ page: 1, page_size: 20, status: '' })
|
const filters = reactive({ page: 1, page_size: 20, status: '' })
|
||||||
|
|
||||||
onMounted(loadList)
|
onMounted(() => {
|
||||||
|
if (siteStore.isDistribution) {
|
||||||
|
router.replace('/seller/listings')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadList()
|
||||||
|
})
|
||||||
|
|
||||||
async function loadList() {
|
async function loadList() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|||||||
@@ -409,6 +409,11 @@
|
|||||||
color: #ea580c;
|
color: #ea580c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pc-growth-badge.is-distribution {
|
||||||
|
background: #ecfdf5;
|
||||||
|
color: #059669;
|
||||||
|
}
|
||||||
|
|
||||||
.pc-realname-badge.is-verified,
|
.pc-realname-badge.is-verified,
|
||||||
.dropdown-status.is-verified {
|
.dropdown-status.is-verified {
|
||||||
background: #ecfdf3;
|
background: #ecfdf3;
|
||||||
@@ -512,6 +517,15 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-growth-panel.is-distribution > div {
|
||||||
|
background: #f0fdf4;
|
||||||
|
border: 1px solid rgba(167, 243, 208, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-growth-panel.is-distribution strong {
|
||||||
|
color: #059669;
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown-status {
|
.dropdown-status {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -48,12 +48,17 @@ const buyerServiceItems = [
|
|||||||
{ label: '使用中', icon: VideoPlay, to: { path: '/orders', query: { tab: 'renting' } } },
|
{ label: '使用中', icon: VideoPlay, to: { path: '/orders', query: { tab: 'renting' } } },
|
||||||
{ label: '已完成', icon: Finished, to: { path: '/orders', query: { tab: 'completed' } } },
|
{ label: '已完成', icon: Finished, to: { path: '/orders', query: { tab: 'completed' } } },
|
||||||
]
|
]
|
||||||
const sellerServiceItems = [
|
const sellerServiceItems = computed(() => {
|
||||||
{ label: '发布商品', icon: CirclePlus, to: '/seller/listings/create' },
|
const items = [
|
||||||
{ label: '我的商品', icon: Shop, to: '/seller/listings' },
|
{ label: '发布商品', icon: CirclePlus, to: '/seller/listings/create' },
|
||||||
{ label: '提号记录', icon: Switch, to: '/seller/pickups' },
|
{ label: '我的商品', icon: Shop, to: '/seller/listings' },
|
||||||
{ label: '提现/账单', icon: Wallet, to: '/wallet' },
|
]
|
||||||
]
|
if (!siteStore.isDistribution) {
|
||||||
|
items.push({ label: '提号记录', icon: Switch, to: '/seller/pickups' })
|
||||||
|
}
|
||||||
|
items.push({ label: '提现/账单', icon: Wallet, to: '/wallet' })
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
const showUserDropdown = ref(false)
|
const showUserDropdown = ref(false)
|
||||||
const supportLoading = ref(false)
|
const supportLoading = ref(false)
|
||||||
@@ -220,7 +225,17 @@ async function handleSupportClick() {
|
|||||||
<span v-else class="pc-avatar-text">{{ session.avatarText }}</span>
|
<span v-else class="pc-avatar-text">{{ session.avatarText }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="pc-user-name">{{ session.displayName }}</span>
|
<span class="pc-user-name">{{ session.displayName }}</span>
|
||||||
<span class="pc-growth-badge" :class="`is-${growthBadgeTone}`">
|
<span
|
||||||
|
v-if="siteStore.isDistribution"
|
||||||
|
class="pc-growth-badge is-distribution"
|
||||||
|
>
|
||||||
|
分销专享
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="pc-growth-badge"
|
||||||
|
:class="`is-${growthBadgeTone}`"
|
||||||
|
>
|
||||||
{{ session.renterGrowthLevelName }}
|
{{ session.renterGrowthLevelName }}
|
||||||
</span>
|
</span>
|
||||||
<span class="pc-realname-badge" :class="`is-${realnameBadge.tone}`">
|
<span class="pc-realname-badge" :class="`is-${realnameBadge.tone}`">
|
||||||
@@ -234,7 +249,17 @@ async function handleSupportClick() {
|
|||||||
<Transition name="dropdown">
|
<Transition name="dropdown">
|
||||||
<div v-if="showUserDropdown" class="pc-user-dropdown-container">
|
<div v-if="showUserDropdown" class="pc-user-dropdown-container">
|
||||||
<div class="pc-user-dropdown">
|
<div class="pc-user-dropdown">
|
||||||
<div class="dropdown-growth-panel">
|
<div v-if="siteStore.isDistribution" class="dropdown-growth-panel is-distribution">
|
||||||
|
<div>
|
||||||
|
<span>所属商城</span>
|
||||||
|
<strong>{{ siteStore.siteName || '专属分销站' }}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>会员权益</span>
|
||||||
|
<strong>渠道特惠直租</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="dropdown-growth-panel">
|
||||||
<div>
|
<div>
|
||||||
<span>租客成长等级</span>
|
<span>租客成长等级</span>
|
||||||
<strong>{{ session.renterGrowthLevelName }}</strong>
|
<strong>{{ session.renterGrowthLevelName }}</strong>
|
||||||
|
|||||||
Reference in New Issue
Block a user