Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
fd57fa49
Unverified
Commit
fd57fa49
authored
Mar 01, 2026
by
Wesley Liddick
Committed by
GitHub
Mar 01, 2026
Browse files
Merge pull request #690 from touwaeriol/pr/bulk-edit-mixed-channel-warning
feat: add mixed-channel warning for bulk account edit
parents
8c4d22b3
c08889b0
Changes
8
Show whitespace changes
Inline
Side-by-side
backend/internal/handler/admin/account_handler.go
View file @
fd57fa49
...
...
@@ -1122,6 +1122,14 @@ func (h *AccountHandler) BulkUpdate(c *gin.Context) {
SkipMixedChannelCheck
:
skipCheck
,
})
if
err
!=
nil
{
var
mixedErr
*
service
.
MixedChannelError
if
errors
.
As
(
err
,
&
mixedErr
)
{
c
.
JSON
(
409
,
gin
.
H
{
"error"
:
"mixed_channel_warning"
,
"message"
:
mixedErr
.
Error
(),
})
return
}
response
.
ErrorFrom
(
c
,
err
)
return
}
...
...
backend/internal/handler/admin/account_handler_mixed_channel_test.go
View file @
fd57fa49
...
...
@@ -19,6 +19,7 @@ func setupAccountMixedChannelRouter(adminSvc *stubAdminService) *gin.Engine {
router
.
POST
(
"/api/v1/admin/accounts/check-mixed-channel"
,
accountHandler
.
CheckMixedChannel
)
router
.
POST
(
"/api/v1/admin/accounts"
,
accountHandler
.
Create
)
router
.
PUT
(
"/api/v1/admin/accounts/:id"
,
accountHandler
.
Update
)
router
.
POST
(
"/api/v1/admin/accounts/bulk-update"
,
accountHandler
.
BulkUpdate
)
return
router
}
...
...
@@ -145,3 +146,53 @@ func TestAccountHandlerUpdateMixedChannelConflictSimplifiedResponse(t *testing.T
require
.
False
(
t
,
hasDetails
)
require
.
False
(
t
,
hasRequireConfirmation
)
}
func
TestAccountHandlerBulkUpdateMixedChannelConflict
(
t
*
testing
.
T
)
{
adminSvc
:=
newStubAdminService
()
adminSvc
.
bulkUpdateAccountErr
=
&
service
.
MixedChannelError
{
GroupID
:
27
,
GroupName
:
"claude-max"
,
CurrentPlatform
:
"Antigravity"
,
OtherPlatform
:
"Anthropic"
,
}
router
:=
setupAccountMixedChannelRouter
(
adminSvc
)
body
,
_
:=
json
.
Marshal
(
map
[
string
]
any
{
"account_ids"
:
[]
int64
{
1
,
2
,
3
},
"group_ids"
:
[]
int64
{
27
},
})
rec
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/api/v1/admin/accounts/bulk-update"
,
bytes
.
NewReader
(
body
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
router
.
ServeHTTP
(
rec
,
req
)
require
.
Equal
(
t
,
http
.
StatusConflict
,
rec
.
Code
)
var
resp
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
rec
.
Body
.
Bytes
(),
&
resp
))
require
.
Equal
(
t
,
"mixed_channel_warning"
,
resp
[
"error"
])
require
.
Contains
(
t
,
resp
[
"message"
],
"claude-max"
)
}
func
TestAccountHandlerBulkUpdateMixedChannelConfirmSkips
(
t
*
testing
.
T
)
{
adminSvc
:=
newStubAdminService
()
router
:=
setupAccountMixedChannelRouter
(
adminSvc
)
body
,
_
:=
json
.
Marshal
(
map
[
string
]
any
{
"account_ids"
:
[]
int64
{
1
,
2
},
"group_ids"
:
[]
int64
{
27
},
"confirm_mixed_channel_risk"
:
true
,
})
rec
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/api/v1/admin/accounts/bulk-update"
,
bytes
.
NewReader
(
body
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
router
.
ServeHTTP
(
rec
,
req
)
require
.
Equal
(
t
,
http
.
StatusOK
,
rec
.
Code
)
var
resp
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
rec
.
Body
.
Bytes
(),
&
resp
))
require
.
Equal
(
t
,
float64
(
0
),
resp
[
"code"
])
data
,
ok
:=
resp
[
"data"
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
Equal
(
t
,
float64
(
2
),
data
[
"success"
])
require
.
Equal
(
t
,
float64
(
0
),
data
[
"failed"
])
}
backend/internal/handler/admin/admin_service_stub_test.go
View file @
fd57fa49
...
...
@@ -24,6 +24,7 @@ type stubAdminService struct {
testedProxyIDs
[]
int64
createAccountErr
error
updateAccountErr
error
bulkUpdateAccountErr
error
checkMixedErr
error
lastMixedCheck
struct
{
accountID
int64
...
...
@@ -235,7 +236,10 @@ func (s *stubAdminService) SetAccountSchedulable(ctx context.Context, id int64,
}
func
(
s
*
stubAdminService
)
BulkUpdateAccounts
(
ctx
context
.
Context
,
input
*
service
.
BulkUpdateAccountsInput
)
(
*
service
.
BulkUpdateAccountsResult
,
error
)
{
return
&
service
.
BulkUpdateAccountsResult
{
Success
:
1
,
Failed
:
0
,
SuccessIDs
:
[]
int64
{
1
}},
nil
if
s
.
bulkUpdateAccountErr
!=
nil
{
return
nil
,
s
.
bulkUpdateAccountErr
}
return
&
service
.
BulkUpdateAccountsResult
{
Success
:
len
(
input
.
AccountIDs
),
Failed
:
0
,
SuccessIDs
:
input
.
AccountIDs
},
nil
}
func
(
s
*
stubAdminService
)
CheckMixedChannelRisk
(
ctx
context
.
Context
,
currentAccountID
int64
,
currentAccountPlatform
string
,
groupIDs
[]
int64
)
error
{
...
...
backend/internal/service/admin_service.go
View file @
fd57fa49
...
...
@@ -1539,17 +1539,13 @@ func (s *adminServiceImpl) BulkUpdateAccounts(ctx context.Context, input *BulkUp
needMixedChannelCheck
:=
input
.
GroupIDs
!=
nil
&&
!
input
.
SkipMixedChannelCheck
// 预加载账号平台信息(混合渠道检查
或 Sora 同步
需要)。
// 预加载账号平台信息(混合渠道检查需要)。
platformByID
:=
map
[
int64
]
string
{}
groupAccountsByID
:=
map
[
int64
][]
Account
{}
groupNameByID
:=
map
[
int64
]
string
{}
if
needMixedChannelCheck
{
accounts
,
err
:=
s
.
accountRepo
.
GetByIDs
(
ctx
,
input
.
AccountIDs
)
if
err
!=
nil
{
if
needMixedChannelCheck
{
return
nil
,
err
}
}
else
{
for
_
,
account
:=
range
accounts
{
if
account
!=
nil
{
platformByID
[
account
.
ID
]
=
account
.
Platform
...
...
@@ -1557,12 +1553,17 @@ func (s *adminServiceImpl) BulkUpdateAccounts(ctx context.Context, input *BulkUp
}
}
loadedAccounts
,
loadedNames
,
err
:=
s
.
preloadMixedChannelRiskData
(
ctx
,
*
input
.
GroupIDs
)
if
err
!=
nil
{
// 预检查混合渠道风险:在任何写操作之前,若发现风险立即返回错误。
if
needMixedChannelCheck
{
for
_
,
accountID
:=
range
input
.
AccountIDs
{
platform
:=
platformByID
[
accountID
]
if
platform
==
""
{
continue
}
if
err
:=
s
.
checkMixedChannelRisk
(
ctx
,
accountID
,
platform
,
*
input
.
GroupIDs
);
err
!=
nil
{
return
nil
,
err
}
groupAccountsByID
=
loadedAccounts
groupNameByID
=
loadedNames
}
}
if
input
.
RateMultiplier
!=
nil
{
...
...
@@ -1606,34 +1607,8 @@ func (s *adminServiceImpl) BulkUpdateAccounts(ctx context.Context, input *BulkUp
// Handle group bindings per account (requires individual operations).
for
_
,
accountID
:=
range
input
.
AccountIDs
{
entry
:=
BulkUpdateAccountResult
{
AccountID
:
accountID
}
platform
:=
""
if
input
.
GroupIDs
!=
nil
{
// 检查混合渠道风险(除非用户已确认)
if
!
input
.
SkipMixedChannelCheck
{
platform
=
platformByID
[
accountID
]
if
platform
==
""
{
account
,
err
:=
s
.
accountRepo
.
GetByID
(
ctx
,
accountID
)
if
err
!=
nil
{
entry
.
Success
=
false
entry
.
Error
=
err
.
Error
()
result
.
Failed
++
result
.
FailedIDs
=
append
(
result
.
FailedIDs
,
accountID
)
result
.
Results
=
append
(
result
.
Results
,
entry
)
continue
}
platform
=
account
.
Platform
}
if
err
:=
s
.
checkMixedChannelRiskWithPreloaded
(
accountID
,
platform
,
*
input
.
GroupIDs
,
groupAccountsByID
,
groupNameByID
);
err
!=
nil
{
entry
.
Success
=
false
entry
.
Error
=
err
.
Error
()
result
.
Failed
++
result
.
FailedIDs
=
append
(
result
.
FailedIDs
,
accountID
)
result
.
Results
=
append
(
result
.
Results
,
entry
)
continue
}
}
if
err
:=
s
.
accountRepo
.
BindGroups
(
ctx
,
accountID
,
*
input
.
GroupIDs
);
err
!=
nil
{
entry
.
Success
=
false
entry
.
Error
=
err
.
Error
()
...
...
@@ -1642,9 +1617,6 @@ func (s *adminServiceImpl) BulkUpdateAccounts(ctx context.Context, input *BulkUp
result
.
Results
=
append
(
result
.
Results
,
entry
)
continue
}
if
!
input
.
SkipMixedChannelCheck
&&
platform
!=
""
{
updateMixedChannelPreloadedAccounts
(
groupAccountsByID
,
*
input
.
GroupIDs
,
accountID
,
platform
)
}
}
entry
.
Success
=
true
...
...
@@ -2316,41 +2288,6 @@ func (s *adminServiceImpl) checkMixedChannelRisk(ctx context.Context, currentAcc
return
nil
}
func
(
s
*
adminServiceImpl
)
preloadMixedChannelRiskData
(
ctx
context
.
Context
,
groupIDs
[]
int64
)
(
map
[
int64
][]
Account
,
map
[
int64
]
string
,
error
)
{
accountsByGroup
:=
make
(
map
[
int64
][]
Account
)
groupNameByID
:=
make
(
map
[
int64
]
string
)
if
len
(
groupIDs
)
==
0
{
return
accountsByGroup
,
groupNameByID
,
nil
}
seen
:=
make
(
map
[
int64
]
struct
{},
len
(
groupIDs
))
for
_
,
groupID
:=
range
groupIDs
{
if
groupID
<=
0
{
continue
}
if
_
,
ok
:=
seen
[
groupID
];
ok
{
continue
}
seen
[
groupID
]
=
struct
{}{}
accounts
,
err
:=
s
.
accountRepo
.
ListByGroup
(
ctx
,
groupID
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"get accounts in group %d: %w"
,
groupID
,
err
)
}
accountsByGroup
[
groupID
]
=
accounts
group
,
err
:=
s
.
groupRepo
.
GetByID
(
ctx
,
groupID
)
if
err
!=
nil
{
continue
}
if
group
!=
nil
{
groupNameByID
[
groupID
]
=
group
.
Name
}
}
return
accountsByGroup
,
groupNameByID
,
nil
}
func
(
s
*
adminServiceImpl
)
validateGroupIDsExist
(
ctx
context
.
Context
,
groupIDs
[]
int64
)
error
{
if
len
(
groupIDs
)
==
0
{
return
nil
...
...
@@ -2380,71 +2317,6 @@ func (s *adminServiceImpl) validateGroupIDsExist(ctx context.Context, groupIDs [
return
nil
}
func
(
s
*
adminServiceImpl
)
checkMixedChannelRiskWithPreloaded
(
currentAccountID
int64
,
currentAccountPlatform
string
,
groupIDs
[]
int64
,
accountsByGroup
map
[
int64
][]
Account
,
groupNameByID
map
[
int64
]
string
)
error
{
currentPlatform
:=
getAccountPlatform
(
currentAccountPlatform
)
if
currentPlatform
==
""
{
return
nil
}
for
_
,
groupID
:=
range
groupIDs
{
accounts
:=
accountsByGroup
[
groupID
]
for
_
,
account
:=
range
accounts
{
if
currentAccountID
>
0
&&
account
.
ID
==
currentAccountID
{
continue
}
otherPlatform
:=
getAccountPlatform
(
account
.
Platform
)
if
otherPlatform
==
""
{
continue
}
if
currentPlatform
!=
otherPlatform
{
groupName
:=
fmt
.
Sprintf
(
"Group %d"
,
groupID
)
if
name
:=
strings
.
TrimSpace
(
groupNameByID
[
groupID
]);
name
!=
""
{
groupName
=
name
}
return
&
MixedChannelError
{
GroupID
:
groupID
,
GroupName
:
groupName
,
CurrentPlatform
:
currentPlatform
,
OtherPlatform
:
otherPlatform
,
}
}
}
}
return
nil
}
func
updateMixedChannelPreloadedAccounts
(
accountsByGroup
map
[
int64
][]
Account
,
groupIDs
[]
int64
,
accountID
int64
,
platform
string
)
{
if
len
(
groupIDs
)
==
0
||
accountID
<=
0
||
platform
==
""
{
return
}
for
_
,
groupID
:=
range
groupIDs
{
if
groupID
<=
0
{
continue
}
accounts
:=
accountsByGroup
[
groupID
]
found
:=
false
for
i
:=
range
accounts
{
if
accounts
[
i
]
.
ID
!=
accountID
{
continue
}
accounts
[
i
]
.
Platform
=
platform
found
=
true
break
}
if
!
found
{
accounts
=
append
(
accounts
,
Account
{
ID
:
accountID
,
Platform
:
platform
,
})
}
accountsByGroup
[
groupID
]
=
accounts
}
}
// CheckMixedChannelRisk checks whether target groups contain mixed channels for the current account platform.
func
(
s
*
adminServiceImpl
)
CheckMixedChannelRisk
(
ctx
context
.
Context
,
currentAccountID
int64
,
currentAccountPlatform
string
,
groupIDs
[]
int64
)
error
{
return
s
.
checkMixedChannelRisk
(
ctx
,
currentAccountID
,
currentAccountPlatform
,
groupIDs
)
...
...
backend/internal/service/admin_service_bulk_update_test.go
View file @
fd57fa49
...
...
@@ -139,34 +139,34 @@ func TestAdminService_BulkUpdateAccounts_NilGroupRepoReturnsError(t *testing.T)
require
.
Contains
(
t
,
err
.
Error
(),
"group repository not configured"
)
}
func
TestAdminService_BulkUpdateAccounts_MixedChannelCheckUsesUpdatedSnapshot
(
t
*
testing
.
T
)
{
// TestAdminService_BulkUpdateAccounts_MixedChannelPreCheckBlocksOnExistingConflict verifies
// that the global pre-check detects a conflict with existing group members and returns an
// error before any DB write is performed.
func
TestAdminService_BulkUpdateAccounts_MixedChannelPreCheckBlocksOnExistingConflict
(
t
*
testing
.
T
)
{
repo
:=
&
accountRepoStubForBulkUpdate
{
getByIDsAccounts
:
[]
*
Account
{
{
ID
:
1
,
Platform
:
PlatformAnthropic
},
{
ID
:
2
,
Platform
:
PlatformAntigravity
},
{
ID
:
1
,
Platform
:
PlatformAntigravity
},
},
// Group 10 already contains an Anthropic account.
listByGroupData
:
map
[
int64
][]
Account
{
10
:
{},
10
:
{
{
ID
:
99
,
Platform
:
PlatformAnthropic
}
},
},
}
svc
:=
&
adminServiceImpl
{
accountRepo
:
repo
,
groupRepo
:
&
groupRepoStubForAdmin
{
getByID
:
&
Group
{
ID
:
10
,
Name
:
"
目标分组
"
}},
groupRepo
:
&
groupRepoStubForAdmin
{
getByID
:
&
Group
{
ID
:
10
,
Name
:
"
target-group
"
}},
}
groupIDs
:=
[]
int64
{
10
}
input
:=
&
BulkUpdateAccountsInput
{
AccountIDs
:
[]
int64
{
1
,
2
},
AccountIDs
:
[]
int64
{
1
},
GroupIDs
:
&
groupIDs
,
}
result
,
err
:=
svc
.
BulkUpdateAccounts
(
context
.
Background
(),
input
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
1
,
result
.
Success
)
require
.
Equal
(
t
,
1
,
result
.
Failed
)
require
.
ElementsMatch
(
t
,
[]
int64
{
1
},
result
.
SuccessIDs
)
require
.
ElementsMatch
(
t
,
[]
int64
{
2
},
result
.
FailedIDs
)
require
.
Len
(
t
,
result
.
Results
,
2
)
require
.
Contains
(
t
,
result
.
Results
[
1
]
.
Error
,
"mixed channel"
)
require
.
Equal
(
t
,
[]
int64
{
1
},
repo
.
bindGroupsCalls
)
require
.
Nil
(
t
,
result
)
require
.
Error
(
t
,
err
)
require
.
Contains
(
t
,
err
.
Error
(),
"mixed channel"
)
// No BindGroups should have been called since the check runs before any write.
require
.
Empty
(
t
,
repo
.
bindGroupsCalls
)
}
frontend/src/api/client.ts
View file @
fd57fa49
...
...
@@ -267,6 +267,7 @@ apiClient.interceptors.response.use(
return
Promise
.
reject
({
status
,
code
:
apiData
.
code
,
error
:
apiData
.
error
,
message
:
apiData
.
message
||
apiData
.
detail
||
error
.
message
})
}
...
...
frontend/src/components/account/BulkEditAccountModal.vue
View file @
fd57fa49
...
...
@@ -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
[]
>
([])
...
...
@@ -1237,10 +1252,46 @@ const buildUpdatePayload = (): Record<string, unknown> | null => {
return
Object
.
keys
(
updates
).
length
>
0
?
updates
:
null
}
const
mixedChannelConfirmed
=
ref
(
false
)
// 是否需要预检查:改了分组 + 全是单一的 antigravity 或 anthropic 平台
// 多平台混合的情况由 submitBulkUpdate 的 409 catch 兜底
const
canPreCheck
=
()
=>
enableGroups
.
value
&&
groupIds
.
value
.
length
>
0
&&
props
.
selectedPlatforms
.
length
===
1
&&
(
props
.
selectedPlatforms
[
0
]
===
'
antigravity
'
||
props
.
selectedPlatforms
[
0
]
===
'
anthropic
'
)
const
handleClose
=
()
=>
{
showMixedChannelWarning
.
value
=
false
mixedChannelWarningMessage
.
value
=
''
pendingUpdatesForConfirm
.
value
=
null
mixedChannelConfirmed
.
value
=
false
emit
(
'
close
'
)
}
// 预检查:提交前调接口检测,有风险就弹窗阻止,返回 false 表示需要用户确认
const
preCheckMixedChannelRisk
=
async
(
built
:
Record
<
string
,
unknown
>
):
Promise
<
boolean
>
=>
{
if
(
!
canPreCheck
())
return
true
if
(
mixedChannelConfirmed
.
value
)
return
true
try
{
const
result
=
await
adminAPI
.
accounts
.
checkMixedChannelRisk
({
platform
:
props
.
selectedPlatforms
[
0
],
group_ids
:
groupIds
.
value
}
)
if
(
!
result
.
has_risk
)
return
true
pendingUpdatesForConfirm
.
value
=
built
mixedChannelWarningMessage
.
value
=
result
.
message
||
t
(
'
admin.accounts.bulkEdit.failed
'
)
showMixedChannelWarning
.
value
=
true
return
false
}
catch
(
error
:
any
)
{
appStore
.
showError
(
error
.
message
||
t
(
'
admin.accounts.bulkEdit.failed
'
))
return
false
}
}
const
handleSubmit
=
async
()
=>
{
if
(
props
.
accountIds
.
length
===
0
)
{
appStore
.
showError
(
t
(
'
admin.accounts.bulkEdit.noSelection
'
))
...
...
@@ -1265,12 +1316,24 @@ const handleSubmit = async () => {
return
}
const
updates
=
buildUpdatePayload
()
if
(
!
updates
)
{
const
built
=
buildUpdatePayload
()
if
(
!
built
)
{
appStore
.
showError
(
t
(
'
admin.accounts.bulkEdit.noFieldsSelected
'
))
return
}
const
canContinue
=
await
preCheckMixedChannelRisk
(
built
)
if
(
!
canContinue
)
return
await
submitBulkUpdate
(
built
)
}
const
submitBulkUpdate
=
async
(
baseUpdates
:
Record
<
string
,
unknown
>
)
=>
{
// 无论是预检查确认还是 409 兜底确认,只要 mixedChannelConfirmed 为 true 就带上 flag
const
updates
=
mixedChannelConfirmed
.
value
?
{
...
baseUpdates
,
confirm_mixed_channel_risk
:
true
}
:
baseUpdates
submitting
.
value
=
true
try
{
...
...
@@ -1287,17 +1350,38 @@ 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
'
))
// 兜底:多平台混合场景下,预检查跳过,由后端 409 触发确认框
if
(
error
.
status
===
409
&&
error
.
error
===
'
mixed_channel_warning
'
)
{
pendingUpdatesForConfirm
.
value
=
baseUpdates
mixedChannelWarningMessage
.
value
=
error
.
message
showMixedChannelWarning
.
value
=
true
}
else
{
appStore
.
showError
(
error
.
message
||
t
(
'
admin.accounts.bulkEdit.failed
'
))
console
.
error
(
'
Error bulk updating accounts:
'
,
error
)
}
}
finally
{
submitting
.
value
=
false
}
}
const
handleMixedChannelConfirm
=
async
()
=>
{
showMixedChannelWarning
.
value
=
false
mixedChannelConfirmed
.
value
=
true
if
(
pendingUpdatesForConfirm
.
value
)
{
await
submitBulkUpdate
(
pendingUpdatesForConfirm
.
value
)
}
}
const
handleMixedChannelCancel
=
()
=>
{
showMixedChannelWarning
.
value
=
false
pendingUpdatesForConfirm
.
value
=
null
}
// Reset form when modal closes
watch
(
()
=>
props
.
show
,
...
...
@@ -1330,10 +1414,12 @@ 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
mixedChannelConfirmed
.
value
=
false
}
}
)
...
...
frontend/src/components/account/EditAccountModal.vue
View file @
fd57fa49
...
...
@@ -1961,7 +1961,7 @@ const ensureAntigravityMixedChannelConfirmed = async (onConfirm: () => Promise<v
}
)
return
false
}
catch
(
error
:
any
)
{
appStore
.
showError
(
error
.
response
?.
data
?.
message
||
error
.
response
?.
data
?.
detail
||
t
(
'
admin.accounts.failedToUpdate
'
))
appStore
.
showError
(
error
.
message
||
t
(
'
admin.accounts.failedToUpdate
'
))
return
false
}
}
...
...
@@ -1984,9 +1984,9 @@ const submitUpdateAccount = async (accountID: number, updatePayload: Record<stri
emit
(
'
updated
'
,
updatedAccount
)
handleClose
()
}
catch
(
error
:
any
)
{
if
(
error
.
response
?.
status
===
409
&&
error
.
response
?.
data
?.
error
===
'
mixed_channel_warning
'
&&
needsMixedChannelCheck
())
{
if
(
error
.
status
===
409
&&
error
.
error
===
'
mixed_channel_warning
'
&&
needsMixedChannelCheck
())
{
openMixedChannelDialog
({
message
:
error
.
response
?.
data
?.
message
,
message
:
error
.
message
,
onConfirm
:
async
()
=>
{
antigravityMixedChannelConfirmed
.
value
=
true
await
submitUpdateAccount
(
accountID
,
updatePayload
)
...
...
@@ -1994,7 +1994,7 @@ const submitUpdateAccount = async (accountID: number, updatePayload: Record<stri
}
)
return
}
appStore
.
showError
(
error
.
response
?.
data
?.
message
||
error
.
response
?.
data
?.
detail
||
t
(
'
admin.accounts.failedToUpdate
'
))
appStore
.
showError
(
error
.
message
||
t
(
'
admin.accounts.failedToUpdate
'
))
}
finally
{
submitting
.
value
=
false
}
...
...
@@ -2245,7 +2245,7 @@ const handleSubmit = async () => {
await
submitUpdateAccount
(
accountID
,
updatePayload
)
}
catch
(
error
:
any
)
{
appStore
.
showError
(
error
.
response
?.
data
?.
message
||
error
.
response
?.
data
?.
detail
||
t
(
'
admin.accounts.failedToUpdate
'
))
appStore
.
showError
(
error
.
message
||
t
(
'
admin.accounts.failedToUpdate
'
))
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment