mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-24 16:05:44 +08:00
feat(subscription): 支持恢复已撤销订阅
This commit is contained in:
@@ -24,7 +24,7 @@ export async function list(
|
||||
page: number = 1,
|
||||
pageSize: number = 20,
|
||||
filters?: {
|
||||
status?: 'active' | 'expired' | 'revoked'
|
||||
status?: 'active' | 'expired' | 'revoked' | 'suspended'
|
||||
user_id?: number
|
||||
group_id?: number
|
||||
platform?: string
|
||||
@@ -121,6 +121,16 @@ export async function revoke(id: number): Promise<{ message: string }> {
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore revoked subscription
|
||||
* @param id - Subscription ID
|
||||
* @returns Restored subscription
|
||||
*/
|
||||
export async function restore(id: number): Promise<UserSubscription> {
|
||||
const { data } = await apiClient.post<UserSubscription>(`/admin/subscriptions/${id}/restore`)
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset daily, weekly, and/or monthly usage quota for a subscription
|
||||
* @param id - Subscription ID
|
||||
@@ -188,6 +198,7 @@ export const subscriptionsAPI = {
|
||||
bulkAssign,
|
||||
extend,
|
||||
revoke,
|
||||
restore,
|
||||
resetQuota,
|
||||
listByGroup,
|
||||
listByUser
|
||||
|
||||
@@ -2977,6 +2977,7 @@ export default {
|
||||
assignSubscription: 'Assign Subscription',
|
||||
adjustSubscription: 'Adjust Subscription',
|
||||
revokeSubscription: 'Revoke Subscription',
|
||||
restoreSubscription: 'Restore Subscription',
|
||||
allStatus: 'All Status',
|
||||
allGroups: 'All Groups',
|
||||
allPlatforms: 'All Platforms',
|
||||
@@ -2999,7 +3000,8 @@ export default {
|
||||
status: {
|
||||
active: 'Active',
|
||||
expired: 'Expired',
|
||||
revoked: 'Revoked'
|
||||
revoked: 'Revoked',
|
||||
suspended: 'Suspended'
|
||||
},
|
||||
columns: {
|
||||
user: 'User',
|
||||
@@ -3028,6 +3030,7 @@ export default {
|
||||
adjust: 'Adjust',
|
||||
adjusting: 'Adjusting...',
|
||||
revoke: 'Revoke',
|
||||
restore: 'Restore',
|
||||
resetQuota: 'Reset Quota',
|
||||
resetQuotaTitle: 'Reset Usage Quota',
|
||||
resetQuotaConfirm: "Reset the daily, weekly, and monthly usage quota for '{user}'? Usage will be zeroed and windows restarted from today.",
|
||||
@@ -3038,17 +3041,21 @@ export default {
|
||||
subscriptionAssigned: 'Subscription assigned successfully',
|
||||
subscriptionAdjusted: 'Subscription adjusted successfully',
|
||||
subscriptionRevoked: 'Subscription revoked successfully',
|
||||
subscriptionRestored: 'Subscription restored successfully',
|
||||
failedToLoad: 'Failed to load subscriptions',
|
||||
failedToAssign: 'Failed to assign subscription',
|
||||
failedToAdjust: 'Failed to adjust subscription',
|
||||
failedToRevoke: 'Failed to revoke subscription',
|
||||
failedToRestore: 'Failed to restore subscription',
|
||||
adjustWouldExpire: 'Remaining days after adjustment must be greater than 0',
|
||||
adjustOutOfRange: 'Adjustment days must be between -36500 and 36500',
|
||||
pleaseSelectUser: 'Please select a user',
|
||||
pleaseSelectGroup: 'Please select a group',
|
||||
validityDaysRequired: 'Please enter a valid number of days (at least 1)',
|
||||
revokeConfirm:
|
||||
"Are you sure you want to revoke the subscription for '{user}'? This action cannot be undone.",
|
||||
"Are you sure you want to revoke the subscription for '{user}'? You can restore it later from the revoked list.",
|
||||
restoreConfirm:
|
||||
"Restore the subscription for '{user}'? If the original subscription has expired, it will be restored as expired.",
|
||||
guide: {
|
||||
title: 'Subscription Management Guide',
|
||||
subtitle: 'Subscription mode lets you assign time-based usage quotas to users, with daily/weekly/monthly limits. Follow these steps to get started.',
|
||||
|
||||
@@ -3054,6 +3054,7 @@ export default {
|
||||
assignSubscription: '分配订阅',
|
||||
adjustSubscription: '调整订阅',
|
||||
revokeSubscription: '撤销订阅',
|
||||
restoreSubscription: '恢复订阅',
|
||||
allStatus: '全部状态',
|
||||
allGroups: '全部分组',
|
||||
allPlatforms: '全部平台',
|
||||
@@ -3076,7 +3077,8 @@ export default {
|
||||
status: {
|
||||
active: '生效中',
|
||||
expired: '已过期',
|
||||
revoked: '已撤销'
|
||||
revoked: '已撤销',
|
||||
suspended: '已暂停'
|
||||
},
|
||||
columns: {
|
||||
user: '用户',
|
||||
@@ -3105,6 +3107,7 @@ export default {
|
||||
adjust: '调整',
|
||||
adjusting: '调整中...',
|
||||
revoke: '撤销',
|
||||
restore: '恢复',
|
||||
resetQuota: '重置配额',
|
||||
resetQuotaTitle: '重置用量配额',
|
||||
resetQuotaConfirm: "确定要重置 '{user}' 的每日、每周和每月用量配额吗?用量将归零并从今天开始重新计算。",
|
||||
@@ -3115,16 +3118,19 @@ export default {
|
||||
subscriptionAssigned: '订阅分配成功',
|
||||
subscriptionAdjusted: '订阅调整成功',
|
||||
subscriptionRevoked: '订阅撤销成功',
|
||||
subscriptionRestored: '订阅已恢复',
|
||||
failedToLoad: '加载订阅列表失败',
|
||||
failedToAssign: '分配订阅失败',
|
||||
failedToAdjust: '调整订阅失败',
|
||||
failedToRevoke: '撤销订阅失败',
|
||||
failedToRestore: '恢复订阅失败',
|
||||
adjustWouldExpire: '调整后剩余天数必须大于0',
|
||||
adjustOutOfRange: '调整天数必须在 -36500 到 36500 之间',
|
||||
pleaseSelectUser: '请选择用户',
|
||||
pleaseSelectGroup: '请选择分组',
|
||||
validityDaysRequired: '请输入有效的天数(至少1天)',
|
||||
revokeConfirm: "确定要撤销 '{user}' 的订阅吗?此操作无法撤销。",
|
||||
revokeConfirm: "确定要撤销 '{user}' 的订阅吗?可稍后在已撤销列表中恢复。",
|
||||
restoreConfirm: "确定要恢复 '{user}' 的订阅吗?如果原订阅已过期,恢复后将显示为已过期。",
|
||||
guide: {
|
||||
title: '订阅管理教程',
|
||||
subtitle: '订阅模式允许你按时间周期为用户分配使用额度,支持日/周/月配额限制。按照以下步骤即可完成配置。',
|
||||
|
||||
@@ -1602,7 +1602,7 @@ export interface UserSubscription {
|
||||
id: number
|
||||
user_id: number
|
||||
group_id: number
|
||||
status: 'active' | 'expired' | 'revoked'
|
||||
status: 'active' | 'expired' | 'revoked' | 'suspended'
|
||||
starts_at: string
|
||||
daily_usage_usd: number
|
||||
weekly_usage_usd: number
|
||||
|
||||
@@ -404,6 +404,14 @@
|
||||
<Icon name="ban" size="sm" />
|
||||
<span class="text-xs">{{ t('admin.subscriptions.revoke') }}</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="row.status === 'revoked'"
|
||||
@click="handleRestore(row)"
|
||||
class="flex flex-col items-center gap-0.5 rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-green-50 hover:text-green-600 dark:hover:bg-green-900/20 dark:hover:text-green-400"
|
||||
>
|
||||
<Icon name="refresh" size="sm" />
|
||||
<span class="text-xs">{{ t('admin.subscriptions.restore') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -645,6 +653,17 @@
|
||||
@cancel="showRevokeDialog = false"
|
||||
/>
|
||||
|
||||
<!-- Restore Confirmation Dialog -->
|
||||
<ConfirmDialog
|
||||
:show="showRestoreDialog"
|
||||
:title="t('admin.subscriptions.restoreSubscription')"
|
||||
:message="t('admin.subscriptions.restoreConfirm', { user: restoringSubscription?.user?.email })"
|
||||
:confirm-text="t('admin.subscriptions.restore')"
|
||||
:cancel-text="t('common.cancel')"
|
||||
@confirm="confirmRestore"
|
||||
@cancel="showRestoreDialog = false"
|
||||
/>
|
||||
|
||||
<!-- Reset Quota Confirmation Dialog -->
|
||||
<ConfirmDialog
|
||||
:show="showResetQuotaConfirm"
|
||||
@@ -940,12 +959,14 @@ const pagination = reactive({
|
||||
const showAssignModal = ref(false)
|
||||
const showExtendModal = ref(false)
|
||||
const showRevokeDialog = ref(false)
|
||||
const showRestoreDialog = ref(false)
|
||||
const showResetQuotaConfirm = ref(false)
|
||||
const submitting = ref(false)
|
||||
const resettingSubscription = ref<UserSubscription | null>(null)
|
||||
const resettingQuota = ref(false)
|
||||
const extendingSubscription = ref<UserSubscription | null>(null)
|
||||
const revokingSubscription = ref<UserSubscription | null>(null)
|
||||
const restoringSubscription = ref<UserSubscription | null>(null)
|
||||
|
||||
const assignForm = reactive({
|
||||
user_id: null as number | null,
|
||||
@@ -1261,6 +1282,26 @@ const confirmRevoke = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleRestore = (subscription: UserSubscription) => {
|
||||
restoringSubscription.value = subscription
|
||||
showRestoreDialog.value = true
|
||||
}
|
||||
|
||||
const confirmRestore = async () => {
|
||||
if (!restoringSubscription.value) return
|
||||
|
||||
try {
|
||||
await adminAPI.subscriptions.restore(restoringSubscription.value.id)
|
||||
appStore.showSuccess(t('admin.subscriptions.subscriptionRestored'))
|
||||
showRestoreDialog.value = false
|
||||
restoringSubscription.value = null
|
||||
loadSubscriptions()
|
||||
} catch (error: any) {
|
||||
appStore.showError(error.response?.data?.detail || t('admin.subscriptions.failedToRestore'))
|
||||
console.error('Error restoring subscription:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleResetQuota = (subscription: UserSubscription) => {
|
||||
resettingSubscription.value = subscription
|
||||
showResetQuotaConfirm.value = true
|
||||
|
||||
Reference in New Issue
Block a user