feat(admin-frontend): 完成订阅与系统管理真实工作台

补齐订单、优惠券、主题、插件、公告与支付管理页面,
接入对应后台接口、路由入口与工具层类型定义。
同时修复套餐页开关初始化误写问题,避免浏览即触发写操作。

在订阅协议侧为 Stash 导出增加 AnyTLS 版本守卫,
未知版本或低于 3.3.0 时不再导出该协议,并补充回归测试与知识记录。
This commit is contained in:
yinjianm
2026-04-24 16:52:41 +08:00
parent 16203b14f6
commit f7cef30b9c
89 changed files with 11122 additions and 92 deletions
+229
View File
@@ -1,13 +1,32 @@
import { adminClient } from './client'
import type {
AdminCouponFetchParams,
AdminCouponGeneratePayload,
AdminCouponListItem,
AdminConfigGroupKey,
AdminConfigMappings,
AdminOrderAssignPayload,
AdminOrderDetail,
AdminOrderFetchParams,
AdminOrderListItem,
AdminKnowledgeDetail,
AdminKnowledgeListItem,
AdminKnowledgeSavePayload,
AdminNoticeItem,
AdminNoticeSavePayload,
AdminNodeItem,
AdminNodeUpdatePayload,
AdminPaymentConfigFields,
AdminPaymentListItem,
AdminPaymentSavePayload,
AdminQueueFailedJobResult,
AdminPaginationResult,
AdminPlanListItem,
AdminPlanSavePayload,
AdminThemeConfigRecord,
AdminThemeListResult,
AdminPluginItem,
AdminPluginTypeItem,
AdminServerGroupItem,
AdminTicketDetail,
AdminTicketFetchParams,
@@ -110,6 +129,86 @@ export function getPlans(): Promise<ApiResponse<AdminPlanListItem[]>> {
return unwrap<AdminPlanListItem[]>('/plan/fetch')
}
export function fetchOrders(params: AdminOrderFetchParams): Promise<AdminPaginationResult<AdminOrderListItem>> {
return adminClient
.get<AdminPaginationResult<AdminOrderListItem>>('/order/fetch', { params })
.then((res) => res.data)
}
export function getOrderDetail(id: number): Promise<ApiResponse<AdminOrderDetail>> {
return unwrapPost<AdminOrderDetail>('/order/detail', { id })
}
export function assignOrder(payload: AdminOrderAssignPayload): Promise<ApiResponse<string>> {
return unwrapPost<string>('/order/assign', payload as unknown as Record<string, unknown>)
}
export function markOrderPaid(tradeNo: string): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/order/paid', { trade_no: tradeNo })
}
export function cancelOrder(tradeNo: string): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/order/cancel', { trade_no: tradeNo })
}
export function updateOrderCommissionStatus(tradeNo: string, commissionStatus: number): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/order/update', {
trade_no: tradeNo,
commission_status: commissionStatus,
})
}
export function getThemes(): Promise<ApiResponse<AdminThemeListResult>> {
return unwrap<AdminThemeListResult>('/theme/getThemes')
}
export function getThemeConfig(name: string): Promise<ApiResponse<AdminThemeConfigRecord>> {
return unwrapPost<AdminThemeConfigRecord>('/theme/getThemeConfig', { name })
}
export function saveThemeConfig(
name: string,
config: AdminThemeConfigRecord,
): Promise<ApiResponse<AdminThemeConfigRecord>> {
return unwrapPost<AdminThemeConfigRecord>('/theme/saveThemeConfig', { name, config })
}
export function uploadTheme(file: File): Promise<ApiResponse<boolean>> {
const formData = new FormData()
formData.append('file', file)
return adminClient
.post<ApiResponse<boolean>>('/theme/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
})
.then((res) => res.data)
}
export function fetchCoupons(params: AdminCouponFetchParams = {}): Promise<AdminPaginationResult<AdminCouponListItem>> {
return adminClient
.get<AdminPaginationResult<AdminCouponListItem>>('/coupon/fetch', {
params: {
current: params.current,
pageSize: params.pageSize,
},
})
.then((res) => res.data)
}
export function saveCoupon(payload: AdminCouponGeneratePayload): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/coupon/generate', payload as unknown as Record<string, unknown>)
}
export function updateCoupon(id: number, payload: Pick<AdminCouponListItem, 'show'>): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/coupon/update', {
id,
...payload,
})
}
export function deleteCoupon(id: number): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/coupon/drop', { id })
}
export function fetchAdminConfig(key?: AdminConfigGroupKey): Promise<ApiResponse<AdminConfigMappings>> {
return unwrap<AdminConfigMappings>('/config/fetch', key ? { key } : undefined)
}
@@ -128,6 +227,136 @@ export function setTelegramWebhook(payload: {
return unwrapPost<Record<string, unknown>>('/config/setTelegramWebhook', payload)
}
export function getKnowledges(): Promise<ApiResponse<AdminKnowledgeListItem[]>> {
return unwrap<AdminKnowledgeListItem[]>('/knowledge/fetch')
}
export function getKnowledgeById(id: number): Promise<ApiResponse<AdminKnowledgeDetail>> {
return unwrap<AdminKnowledgeDetail>('/knowledge/fetch', { id })
}
export function getKnowledgeCategories(): Promise<ApiResponse<string[]>> {
return unwrap<string[]>('/knowledge/getCategory')
}
export function saveKnowledge(payload: AdminKnowledgeSavePayload): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/knowledge/save', payload as unknown as Record<string, unknown>)
}
export function toggleKnowledgeVisibility(id: number): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/knowledge/show', { id })
}
export function deleteKnowledge(id: number): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/knowledge/drop', { id })
}
export function sortKnowledges(ids: number[]): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/knowledge/sort', { ids })
}
export function fetchNotices(): Promise<ApiResponse<AdminNoticeItem[]>> {
return unwrap<AdminNoticeItem[]>('/notice/fetch')
}
export function saveNotice(payload: AdminNoticeSavePayload): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/notice/save', payload as unknown as Record<string, unknown>)
}
export function toggleNoticeVisibility(id: number): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/notice/show', { id })
}
export function deleteNotice(id: number): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/notice/drop', { id })
}
export function sortNotices(ids: number[]): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/notice/sort', { ids })
}
export function fetchPayments(): Promise<ApiResponse<AdminPaymentListItem[]>> {
return unwrap<AdminPaymentListItem[]>('/payment/fetch')
}
export function getPaymentMethods(): Promise<ApiResponse<string[]>> {
return unwrap<string[]>('/payment/getPaymentMethods')
}
export function getPaymentForm(payload: {
payment: string
id?: number
}): Promise<ApiResponse<AdminPaymentConfigFields>> {
return unwrapPost<AdminPaymentConfigFields>('/payment/getPaymentForm', payload as unknown as Record<string, unknown>)
}
export function savePayment(payload: AdminPaymentSavePayload): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/payment/save', payload as unknown as Record<string, unknown>)
}
export function togglePaymentVisibility(id: number): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/payment/show', { id })
}
export function deletePayment(id: number): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/payment/drop', { id })
}
export function sortPayments(ids: number[]): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/payment/sort', { ids })
}
export function getPluginTypes(): Promise<ApiResponse<AdminPluginTypeItem[]>> {
return unwrap<AdminPluginTypeItem[]>('/plugin/types')
}
export function getPlugins(params: {
type?: string
} = {}): Promise<ApiResponse<AdminPluginItem[]>> {
return unwrap<AdminPluginItem[]>('/plugin/getPlugins', params)
}
export function installPlugin(code: string): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/plugin/install', { code })
}
export function uninstallPlugin(code: string): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/plugin/uninstall', { code })
}
export function enablePlugin(code: string): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/plugin/enable', { code })
}
export function disablePlugin(code: string): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/plugin/disable', { code })
}
export function getPluginConfig(code: string): Promise<ApiResponse<Record<string, unknown>>> {
return unwrap<Record<string, unknown>>('/plugin/config', { code })
}
export function savePluginConfig(code: string, config: Record<string, unknown>): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/plugin/config', { code, config })
}
export function upgradePlugin(code: string): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/plugin/upgrade', { code })
}
export function uploadPluginPackage(file: File): Promise<ApiResponse<boolean>> {
const formData = new FormData()
formData.append('file', file)
return adminClient
.post<ApiResponse<boolean>>('/plugin/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then((res) => res.data)
}
export function savePlan(payload: AdminPlanSavePayload): Promise<ApiResponse<boolean>> {
return unwrapPost<boolean>('/plan/save', payload as unknown as Record<string, unknown>)
}