- 后端新增批量创建二维码接口 POST /admin/chats/qrcodes/batch - 前端二维码管理页支持多图拖拽批量上传 - 注册 qrcode 图片压缩场景(maxSide=2560, quality=0.95) - 后端 normalizeScene 注册 qrcode scene - 增强 AuthImage 组件支持 el-image 大图预览(previewSrcList) - 修复 WithdrawalDetailDialog 提现凭证图片 401 问题 - 删除重复的 components/AuthImage.vue,统一使用共享组件 - 提交3剩余: 会话列表群类型图标、发布成功跳群、管理端路由等
249 lines
7.0 KiB
TypeScript
249 lines
7.0 KiB
TypeScript
import { apiClient } from '@/shared/api/client'
|
|
import type { ApiResponse } from '@/shared/types/types'
|
|
import type { ListingReviewStatus, ListingStatus } from '@/shared/types/status'
|
|
|
|
export interface Listing {
|
|
id: number
|
|
listing_no: string
|
|
account_id: number
|
|
owner_id: number
|
|
owner_phone?: string
|
|
owner_nickname?: string
|
|
title: string
|
|
description: string
|
|
game_name: string
|
|
server_region: string
|
|
login_platform: string
|
|
rank_level: string
|
|
haf_coin_amount: number
|
|
asset_summary?: Record<string, unknown>
|
|
screenshot_urls: string[]
|
|
cover_url: string
|
|
price_cent: number
|
|
deposit_amount_cent: number
|
|
is_accelerated_sale?: boolean
|
|
in_transaction: boolean
|
|
status: ListingStatus
|
|
review_status: ListingReviewStatus
|
|
review_reason: string
|
|
published_at?: string
|
|
listing_group_conversation_id?: number
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface ListingPayload {
|
|
title: string
|
|
description: string
|
|
server_region: string
|
|
login_platform: string
|
|
rank_level: string
|
|
haf_coin_amount: number
|
|
asset_summary?: Record<string, unknown>
|
|
screenshot_urls: string[]
|
|
price_cent: number
|
|
deposit_amount_cent: number
|
|
agreed_virtual_asset_sale: boolean
|
|
agreed_seller_agreement: boolean
|
|
}
|
|
|
|
export interface PublicListingQuery {
|
|
page?: number
|
|
page_size?: number
|
|
keyword?: string
|
|
sort?: string
|
|
zone?: string
|
|
server?: string
|
|
region?: string
|
|
login_method?: string
|
|
rank?: string
|
|
insurance?: string
|
|
stamina?: string
|
|
load?: string
|
|
skin_group?: string
|
|
skin_name?: string
|
|
min_coin?: number
|
|
max_coin?: number
|
|
min_price?: number
|
|
max_price?: number
|
|
min_deposit?: number
|
|
max_deposit?: number
|
|
min_total?: number
|
|
max_total?: number
|
|
min_fire_level?: number
|
|
max_fire_level?: number
|
|
min_secret_kd?: number
|
|
max_secret_kd?: number
|
|
[key: `resource_${string}_min`]: number | undefined
|
|
[key: `resource_${string}_max`]: number | undefined
|
|
}
|
|
|
|
export interface PublicListingPage {
|
|
items: Listing[]
|
|
total: number
|
|
page: number
|
|
page_size: number
|
|
zone_counts: Record<string, number>
|
|
}
|
|
|
|
export async function fetchListings(query: PublicListingQuery = {}) {
|
|
const page = await fetchListingsPage(query)
|
|
return page.items
|
|
}
|
|
|
|
export async function fetchListingsPage(query: PublicListingQuery = {}) {
|
|
const params = Object.fromEntries(
|
|
Object.entries(query).filter(
|
|
([, value]) => value !== '' && value !== undefined && value !== null
|
|
)
|
|
)
|
|
const { data } = await apiClient.get<ApiResponse<Partial<PublicListingPage>>>('/listings', {
|
|
params,
|
|
})
|
|
return normalizePublicListingPage(data.data, query)
|
|
}
|
|
|
|
function normalizePublicListingPage(
|
|
data: Partial<PublicListingPage>,
|
|
query: PublicListingQuery
|
|
): PublicListingPage {
|
|
const items = Array.isArray(data.items) ? data.items : []
|
|
return {
|
|
items,
|
|
total: Number.isFinite(Number(data.total)) ? Number(data.total) : items.length,
|
|
page: Number.isFinite(Number(data.page)) ? Number(data.page) : Number(query.page || 1),
|
|
page_size: Number.isFinite(Number(data.page_size))
|
|
? Number(data.page_size)
|
|
: Number(query.page_size || items.length || 20),
|
|
zone_counts: data.zone_counts && typeof data.zone_counts === 'object' ? data.zone_counts : {},
|
|
}
|
|
}
|
|
|
|
export async function fetchListing(id: string | number) {
|
|
const { data } = await apiClient.get<ApiResponse<Listing>>(`/listings/${id}`)
|
|
return data.data
|
|
}
|
|
|
|
export async function fetchSellerListings() {
|
|
const { data } = await apiClient.get<ApiResponse<{ items: Listing[] }>>('/seller/listings')
|
|
return data.data.items
|
|
}
|
|
|
|
export async function fetchSellerListing(id: string | number) {
|
|
const { data } = await apiClient.get<ApiResponse<Listing>>(`/seller/listings/${id}`)
|
|
return data.data
|
|
}
|
|
|
|
export async function createListing(payload: ListingPayload) {
|
|
const { data } = await apiClient.post<ApiResponse<Listing>>('/listings', payload)
|
|
return data.data
|
|
}
|
|
|
|
export async function updateListing(id: string | number, payload: ListingPayload) {
|
|
const { data } = await apiClient.put<ApiResponse<Listing>>(`/listings/${id}`, payload)
|
|
return data.data
|
|
}
|
|
|
|
export async function submitListingReview(id: number) {
|
|
const { data } = await apiClient.post<ApiResponse<Listing>>(`/listings/${id}/submit-review`)
|
|
return data.data
|
|
}
|
|
|
|
export async function offlineListing(id: number) {
|
|
const { data } = await apiClient.delete<ApiResponse<Listing>>(`/listings/${id}`)
|
|
return data.data
|
|
}
|
|
|
|
export async function fetchPendingReviewListings() {
|
|
const { data } = await apiClient.get<ApiResponse<{ items: Listing[] }>>('/admin/listings/pending')
|
|
return data.data.items
|
|
}
|
|
|
|
export interface AdminListingQuery {
|
|
owner_id?: string
|
|
status?: ListingStatus | ''
|
|
review_status?: ListingReviewStatus | ''
|
|
limit?: number
|
|
page?: number
|
|
page_size?: number
|
|
}
|
|
|
|
export interface AdminListingPage {
|
|
items: Listing[]
|
|
total: number
|
|
page: number
|
|
page_size: number
|
|
}
|
|
|
|
export async function fetchAdminListings(query: AdminListingQuery = {}) {
|
|
const params = Object.fromEntries(
|
|
Object.entries(query).filter(([, value]) => value !== '' && value !== undefined)
|
|
)
|
|
const { data } = await apiClient.get<ApiResponse<AdminListingPage>>('/admin/listings', { params })
|
|
return normalizeAdminListingPage(data.data, query)
|
|
}
|
|
|
|
function normalizeAdminListingPage(
|
|
data: Partial<AdminListingPage>,
|
|
query: AdminListingQuery
|
|
): AdminListingPage {
|
|
const items = Array.isArray(data.items) ? data.items : []
|
|
return {
|
|
items,
|
|
total: Number.isFinite(Number(data.total)) ? Number(data.total) : items.length,
|
|
page: Number.isFinite(Number(data.page)) ? Number(data.page) : Number(query.page || 1),
|
|
page_size: Number.isFinite(Number(data.page_size))
|
|
? Number(data.page_size)
|
|
: Number(query.page_size || items.length || 10),
|
|
}
|
|
}
|
|
|
|
export async function fetchAdminListing(id: string | number) {
|
|
const { data } = await apiClient.get<ApiResponse<Listing>>(`/admin/listings/${id}`)
|
|
return data.data
|
|
}
|
|
|
|
export async function adminOfflineListing(id: number, reason: string) {
|
|
const { data } = await apiClient.post<ApiResponse<Listing>>(`/admin/listings/${id}/offline`, {
|
|
reason,
|
|
})
|
|
return data.data
|
|
}
|
|
|
|
export async function adminMarkListingAbnormal(id: number, reason: string) {
|
|
const { data } = await apiClient.post<ApiResponse<Listing>>(
|
|
`/admin/listings/${id}/mark-abnormal`,
|
|
{ reason }
|
|
)
|
|
return data.data
|
|
}
|
|
|
|
export async function approveListing(id: number) {
|
|
const { data } = await apiClient.post<ApiResponse<Listing>>(`/admin/listings/${id}/approve`)
|
|
return data.data
|
|
}
|
|
|
|
export interface AdminListingPriceAdjustPayload {
|
|
buyer_ratio?: number
|
|
buyer_total_price_cent?: number
|
|
reason?: string
|
|
}
|
|
|
|
export async function adjustListingReviewPrice(
|
|
id: number,
|
|
payload: AdminListingPriceAdjustPayload
|
|
) {
|
|
const { data } = await apiClient.post<ApiResponse<Listing>>(
|
|
`/admin/listings/${id}/adjust-price`,
|
|
payload
|
|
)
|
|
return data.data
|
|
}
|
|
|
|
export async function rejectListing(id: number, reason: string) {
|
|
const { data } = await apiClient.post<ApiResponse<Listing>>(`/admin/listings/${id}/reject`, {
|
|
reason,
|
|
})
|
|
return data.data
|
|
}
|