feat: bulk update accounts pre-check mixed channel risk with confirm dialog

- Move mixed channel check before any DB writes in BulkUpdateAccounts
- Return 409 from BulkUpdate handler for MixedChannelError
- Add ConfirmDialog to BulkEditAccountModal for mixed channel warning
- Update mixed channel warning message to Chinese
This commit is contained in:
erio
2026-02-28 19:31:57 +08:00
parent f7fa71bc28
commit 7aa4c083a9
3 changed files with 75 additions and 37 deletions

View File

@@ -756,6 +756,17 @@
</div>
</template>
</BaseDialog>
<ConfirmDialog
:show="showMixedChannelWarning"
:title="t('admin.accounts.mixedChannelWarningTitle')"
:message="mixedChannelWarningMessage"
:confirm-text="t('common.confirm')"
:cancel-text="t('common.cancel')"
:danger="true"
@confirm="handleMixedChannelConfirm"
@cancel="handleMixedChannelCancel"
/>
</template>
<script setup lang="ts">
@@ -765,6 +776,7 @@ import { useAppStore } from '@/stores/app'
import { adminAPI } from '@/api/admin'
import type { Proxy as ProxyConfig, AdminGroup, AccountPlatform, AccountType } from '@/types'
import BaseDialog from '@/components/common/BaseDialog.vue'
import ConfirmDialog from '@/components/common/ConfirmDialog.vue'
import Select from '@/components/common/Select.vue'
import ProxySelector from '@/components/common/ProxySelector.vue'
import GroupSelector from '@/components/common/GroupSelector.vue'
@@ -844,6 +856,9 @@ const enableRpmLimit = ref(false)
// State - field values
const submitting = ref(false)
const showMixedChannelWarning = ref(false)
const mixedChannelWarningMessage = ref('')
const pendingUpdatesForConfirm = ref<Record<string, unknown> | null>(null)
const baseUrl = ref('')
const modelRestrictionMode = ref<'whitelist' | 'mapping'>('whitelist')
const allowedModels = ref<string[]>([])
@@ -1238,10 +1253,13 @@ const buildUpdatePayload = (): Record<string, unknown> | null => {
}
const handleClose = () => {
showMixedChannelWarning.value = false
mixedChannelWarningMessage.value = ''
pendingUpdatesForConfirm.value = null
emit('close')
}
const handleSubmit = async () => {
const handleSubmit = async (confirmMixedChannel = false) => {
if (props.accountIds.length === 0) {
appStore.showError(t('admin.accounts.bulkEdit.noSelection'))
return
@@ -1265,10 +1283,16 @@ const handleSubmit = async () => {
return
}
const updates = buildUpdatePayload()
if (!updates) {
appStore.showError(t('admin.accounts.bulkEdit.noFieldsSelected'))
return
let updates: Record<string, unknown>
if (confirmMixedChannel && pendingUpdatesForConfirm.value) {
updates = { ...pendingUpdatesForConfirm.value, confirm_mixed_channel_risk: true }
} else {
const built = buildUpdatePayload()
if (!built) {
appStore.showError(t('admin.accounts.bulkEdit.noFieldsSelected'))
return
}
updates = built
}
submitting.value = true
@@ -1287,17 +1311,34 @@ const handleSubmit = async () => {
}
if (success > 0) {
pendingUpdatesForConfirm.value = null
emit('updated')
handleClose()
}
} catch (error: any) {
appStore.showError(error.response?.data?.detail || t('admin.accounts.bulkEdit.failed'))
console.error('Error bulk updating accounts:', error)
if (error.response?.status === 409 && error.response?.data?.error === 'mixed_channel_warning') {
pendingUpdatesForConfirm.value = updates
mixedChannelWarningMessage.value = error.response.data.message
showMixedChannelWarning.value = true
} else {
appStore.showError(error.response?.data?.detail || t('admin.accounts.bulkEdit.failed'))
console.error('Error bulk updating accounts:', error)
}
} finally {
submitting.value = false
}
}
const handleMixedChannelConfirm = async () => {
showMixedChannelWarning.value = false
await handleSubmit(true)
}
const handleMixedChannelCancel = () => {
showMixedChannelWarning.value = false
pendingUpdatesForConfirm.value = null
}
// Reset form when modal closes
watch(
() => props.show,
@@ -1330,10 +1371,11 @@ watch(
rateMultiplier.value = 1
status.value = 'active'
groupIds.value = []
rpmLimitEnabled.value = false
bulkBaseRpm.value = null
bulkRpmStrategy.value = 'tiered'
bulkRpmStickyBuffer.value = null
// Reset mixed channel warning state
showMixedChannelWarning.value = false
mixedChannelWarningMessage.value = ''
pendingUpdatesForConfirm.value = null
}
}
)