596 lines
17 KiB
TypeScript
596 lines
17 KiB
TypeScript
import { clearAdminToken, getAdminToken, setAdminToken, setAdminUser } from './admin-auth'
|
|
|
|
const API_BASE
|
|
= import.meta.env.VITE_API_BASE
|
|
|| (import.meta.env.DEV ? 'http://127.0.0.1:8000/api/v1' : '/api/v1')
|
|
|
|
type RequestError = Error & { status?: number }
|
|
|
|
async function request<T = any>(path: string, init: RequestInit = {}) {
|
|
const token = getAdminToken()
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
...(init.headers as Record<string, string> || {}),
|
|
}
|
|
if (token)
|
|
headers.Authorization = `Bearer ${token}`
|
|
|
|
let resp: Response
|
|
try {
|
|
resp = await fetch(`${API_BASE}${path}`, {
|
|
...init,
|
|
headers,
|
|
})
|
|
}
|
|
catch {
|
|
throw new Error(`接口连接失败:${API_BASE}${path}`)
|
|
}
|
|
|
|
if (resp.status === 401) {
|
|
clearAdminToken()
|
|
throw new Error('登录已失效,请重新登录')
|
|
}
|
|
|
|
const data = await resp.json().catch(() => ({}))
|
|
if (!resp.ok) {
|
|
const message = data?.detail || data?.message || `请求失败(${resp.status})`
|
|
const error = new Error(message) as RequestError
|
|
error.status = resp.status
|
|
throw error
|
|
}
|
|
return data as T
|
|
}
|
|
|
|
export function isRequestNotFound(error: unknown) {
|
|
return (error as RequestError)?.status === 404
|
|
}
|
|
|
|
export async function adminLogin(account: string, password: string) {
|
|
const data = await request<{
|
|
access_token: string
|
|
refresh_token: string
|
|
user: Record<string, any>
|
|
}>('/admin/auth/login', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ account, password }),
|
|
})
|
|
setAdminToken(data.access_token)
|
|
setAdminUser(data.user)
|
|
return data
|
|
}
|
|
|
|
export function adminMe() {
|
|
return request('/admin/auth/me')
|
|
}
|
|
|
|
export function adminDashboard() {
|
|
return request('/admin/dashboard')
|
|
}
|
|
|
|
export function adminModuleDesign() {
|
|
return request('/admin/module-design')
|
|
}
|
|
|
|
export function adminListUsers(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/users?${q.toString()}`)
|
|
}
|
|
|
|
export function adminCreateUser(payload: Record<string, any>) {
|
|
return request('/admin/users', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateUser(userId: number, payload: Record<string, any>) {
|
|
return request(`/admin/users/${userId}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteUser(userId: number) {
|
|
return request(`/admin/users/${userId}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminUserOptions(keyword = '') {
|
|
const q = new URLSearchParams()
|
|
if (keyword.trim())
|
|
q.set('keyword', keyword.trim())
|
|
return request(`/admin/user-options?${q.toString()}`)
|
|
}
|
|
|
|
export function adminListSpots(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/spots?${q.toString()}`)
|
|
}
|
|
|
|
export function adminGetSpot(spotId: number) {
|
|
return request(`/spots/${spotId}`).then((detail: any) => ({
|
|
id: detail.id,
|
|
title: detail.title || '',
|
|
city: detail.city || '',
|
|
creator_id: detail.creator?.id || detail.creator_id || 0,
|
|
longitude: detail.longitude ?? 0,
|
|
latitude: detail.latitude ?? 0,
|
|
description: detail.description || '',
|
|
transport: detail.transport || '',
|
|
best_time: detail.best_time || '',
|
|
difficulty: detail.difficulty || '',
|
|
is_free: detail.is_free ?? true,
|
|
price_min: detail.price_min ?? null,
|
|
price_max: detail.price_max ?? null,
|
|
audit_status: detail.audit_status || 'pending',
|
|
reject_reason: detail.reject_reason || '',
|
|
tag_ids: (detail.tags || []).map((t: any) => t.id),
|
|
image_urls: (detail.images || []).map((img: any) => img.image_url),
|
|
images: detail.images || [],
|
|
}))
|
|
}
|
|
|
|
export function adminCreateSpot(payload: Record<string, any>) {
|
|
return request('/admin/spots', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateSpot(spotId: number, payload: Record<string, any>) {
|
|
return request(`/admin/spots/${spotId}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteSpot(spotId: number) {
|
|
return request(`/admin/spots/${spotId}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminSpotTagOptions(keyword = '') {
|
|
return request('/tags?sort=hot').then((items: any[]) => {
|
|
const key = keyword.trim().toLowerCase()
|
|
const normalized = (items || []).map((item: any) => ({
|
|
id: item.id,
|
|
title: item.name || item.title || '',
|
|
}))
|
|
if (!key)
|
|
return normalized
|
|
return normalized.filter(item => String(item.title).toLowerCase().includes(key))
|
|
})
|
|
}
|
|
|
|
export function adminAuditSpot(spotId: number, payload: { audit_status: string, reject_reason?: string }) {
|
|
return request(`/admin/spots/${spotId}/audit`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminBatchAuditSpots(payload: { ids: number[], audit_status: string, reject_reason?: string }) {
|
|
return request('/admin/spots/batch-audit', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminListEvents(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/events?${q.toString()}`)
|
|
}
|
|
|
|
export function adminGetEvent(eventId: number) {
|
|
return request(`/admin/events/${eventId}`)
|
|
}
|
|
|
|
export function adminCreateEvent(payload: Record<string, any>) {
|
|
return request('/admin/events', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateEvent(eventId: number, payload: Record<string, any>) {
|
|
return request(`/admin/events/${eventId}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteEvent(eventId: number) {
|
|
return request(`/admin/events/${eventId}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminListEventRegistrations(eventId: number) {
|
|
return request(`/admin/events/${eventId}/registrations`)
|
|
}
|
|
|
|
export function adminCreateEventRegistration(eventId: number, payload: Record<string, any>) {
|
|
return request(`/admin/events/${eventId}/registrations`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateEventRegistration(eventId: number, registrationId: number, payload: Record<string, any>) {
|
|
return request(`/admin/events/${eventId}/registrations/${registrationId}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteEventRegistration(eventId: number, registrationId: number) {
|
|
return request(`/admin/events/${eventId}/registrations/${registrationId}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminListEventPhotos(eventId: number) {
|
|
return request(`/admin/events/${eventId}/photos`)
|
|
}
|
|
|
|
export function adminCreateEventPhoto(eventId: number, payload: Record<string, any>) {
|
|
return request(`/admin/events/${eventId}/photos`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateEventPhoto(eventId: number, photoId: number, payload: Record<string, any>) {
|
|
return request(`/admin/events/${eventId}/photos/${photoId}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteEventPhoto(eventId: number, photoId: number) {
|
|
return request(`/admin/events/${eventId}/photos/${photoId}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminAuditEvent(eventId: number, payload: { audit_status: string, reject_reason?: string }) {
|
|
return request(`/admin/events/${eventId}/audit`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminBatchAuditEvents(payload: { ids: number[], audit_status: string, reject_reason?: string }) {
|
|
return request('/admin/events/batch-audit', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminListShooting(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/shooting?${q.toString()}`)
|
|
}
|
|
|
|
export function adminGetShooting(requestId: number) {
|
|
return request(`/admin/shooting/${requestId}`)
|
|
}
|
|
|
|
export function adminCreateShooting(payload: Record<string, any>) {
|
|
return request('/admin/shooting', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateShooting(requestId: number, payload: Record<string, any>) {
|
|
return request(`/admin/shooting/${requestId}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteShooting(requestId: number) {
|
|
return request(`/admin/shooting/${requestId}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminListShootingApplications(requestId: number) {
|
|
return request(`/admin/shooting/${requestId}/applications`)
|
|
}
|
|
|
|
export function adminCreateShootingApplication(requestId: number, payload: Record<string, any>) {
|
|
return request(`/admin/shooting/${requestId}/applications`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateShootingApplication(requestId: number, applicationId: number, payload: Record<string, any>) {
|
|
return request(`/admin/shooting/${requestId}/applications/${applicationId}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteShootingApplication(requestId: number, applicationId: number) {
|
|
return request(`/admin/shooting/${requestId}/applications/${applicationId}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminAuditShooting(requestId: number, payload: { audit_status: string, reject_reason?: string }) {
|
|
return request(`/admin/shooting/${requestId}/audit`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminBatchAuditShooting(payload: { ids: number[], audit_status: string, reject_reason?: string }) {
|
|
return request('/admin/shooting/batch-audit', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminListAppNavConfigs(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/app-nav-configs?${q.toString()}`)
|
|
}
|
|
|
|
export function adminCreateAppNavConfig(payload: Record<string, any>) {
|
|
return request('/admin/app-nav-configs', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateAppNavConfig(id: number, payload: Record<string, any>) {
|
|
return request(`/admin/app-nav-configs/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteAppNavConfig(id: number) {
|
|
return request(`/admin/app-nav-configs/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminListPromotions(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/promotions?${q.toString()}`)
|
|
}
|
|
|
|
export function adminCreatePromotion(payload: Record<string, any>) {
|
|
return request('/admin/promotions', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdatePromotion(id: number, payload: Record<string, any>) {
|
|
return request(`/admin/promotions/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeletePromotion(id: number) {
|
|
return request(`/admin/promotions/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminPromotionLinkOptions(linkType: 'spot' | 'event' | 'shooting', keyword = '') {
|
|
const q = new URLSearchParams()
|
|
q.set('link_type', linkType)
|
|
if (keyword.trim())
|
|
q.set('keyword', keyword.trim())
|
|
return request(`/admin/promotion-link-options?${q.toString()}`)
|
|
}
|
|
|
|
export function adminListMembershipPlans(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/membership/plans?${q.toString()}`)
|
|
}
|
|
|
|
export function adminCreateMembershipPlan(payload: Record<string, any>) {
|
|
return request('/admin/membership/plans', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateMembershipPlan(id: number, payload: Record<string, any>) {
|
|
return request(`/admin/membership/plans/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteMembershipPlan(id: number) {
|
|
return request(`/admin/membership/plans/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminListUserMemberships(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/membership/user-memberships?${q.toString()}`)
|
|
}
|
|
|
|
export function adminCreateUserMembership(payload: Record<string, any>) {
|
|
return request('/admin/membership/user-memberships', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateUserMembership(id: number, payload: Record<string, any>) {
|
|
return request(`/admin/membership/user-memberships/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteUserMembership(id: number) {
|
|
return request(`/admin/membership/user-memberships/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminListPointLedger(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/points/ledger?${q.toString()}`)
|
|
}
|
|
|
|
export function adminAdjustPoints(payload: Record<string, any>) {
|
|
return request('/admin/points/adjust', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminRollbackPointLedger(ledgerId: number) {
|
|
return request(`/admin/points/ledger/${ledgerId}/rollback`, {
|
|
method: 'POST',
|
|
})
|
|
}
|
|
|
|
export function adminListNotifications(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/notifications?${q.toString()}`)
|
|
}
|
|
|
|
export function adminCreateNotification(payload: Record<string, any>) {
|
|
return request('/admin/notifications', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateNotification(id: number, payload: Record<string, any>) {
|
|
return request(`/admin/notifications/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteNotification(id: number) {
|
|
return request(`/admin/notifications/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminListAuditLogs(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/audit-logs?${q.toString()}`)
|
|
}
|
|
|
|
export function adminCreateAuditLog(payload: Record<string, any>) {
|
|
return request('/admin/audit-logs', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminListReports(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/reports?${q.toString()}`)
|
|
}
|
|
|
|
export function adminUpdateReport(id: number, payload: Record<string, any>) {
|
|
return request(`/admin/reports/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteReport(id: number) {
|
|
return request(`/admin/reports/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
export function adminListSystemConfigs(params: Record<string, any>) {
|
|
const q = new URLSearchParams()
|
|
Object.entries(params || {}).forEach(([k, v]) => {
|
|
if (v !== undefined && v !== null && String(v).trim() !== '')
|
|
q.set(k, String(v))
|
|
})
|
|
return request(`/admin/system-configs?${q.toString()}`)
|
|
}
|
|
|
|
export function adminCreateSystemConfig(payload: Record<string, any>) {
|
|
return request('/admin/system-configs', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminUpdateSystemConfig(id: number, payload: Record<string, any>) {
|
|
return request(`/admin/system-configs/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(payload),
|
|
})
|
|
}
|
|
|
|
export function adminDeleteSystemConfig(id: number) {
|
|
return request(`/admin/system-configs/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|