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
8027531d
"vscode:/vscode.git/clone" did not exist on "fc095bf054dddc6e998d9e27fc4029b7449af068"
Commit
8027531d
authored
Mar 19, 2026
by
Hg
Browse files
feat: add ungrouped filter to account
parent
9f6ab6b8
Changes
9
Hide whitespace changes
Inline
Side-by-side
backend/internal/handler/admin/account_handler.go
View file @
8027531d
...
@@ -165,6 +165,8 @@ type AccountWithConcurrency struct {
...
@@ -165,6 +165,8 @@ type AccountWithConcurrency struct {
CurrentRPM
*
int
`json:"current_rpm,omitempty"`
// 当前分钟 RPM 计数
CurrentRPM
*
int
`json:"current_rpm,omitempty"`
// 当前分钟 RPM 计数
}
}
const
accountListGroupUngroupedQueryValue
=
"ungrouped"
func
(
h
*
AccountHandler
)
buildAccountResponseWithRuntime
(
ctx
context
.
Context
,
account
*
service
.
Account
)
AccountWithConcurrency
{
func
(
h
*
AccountHandler
)
buildAccountResponseWithRuntime
(
ctx
context
.
Context
,
account
*
service
.
Account
)
AccountWithConcurrency
{
item
:=
AccountWithConcurrency
{
item
:=
AccountWithConcurrency
{
Account
:
dto
.
AccountFromService
(
account
),
Account
:
dto
.
AccountFromService
(
account
),
...
@@ -226,7 +228,20 @@ func (h *AccountHandler) List(c *gin.Context) {
...
@@ -226,7 +228,20 @@ func (h *AccountHandler) List(c *gin.Context) {
var
groupID
int64
var
groupID
int64
if
groupIDStr
:=
c
.
Query
(
"group"
);
groupIDStr
!=
""
{
if
groupIDStr
:=
c
.
Query
(
"group"
);
groupIDStr
!=
""
{
groupID
,
_
=
strconv
.
ParseInt
(
groupIDStr
,
10
,
64
)
if
groupIDStr
==
accountListGroupUngroupedQueryValue
{
groupID
=
service
.
AccountListGroupUngrouped
}
else
{
parsedGroupID
,
parseErr
:=
strconv
.
ParseInt
(
groupIDStr
,
10
,
64
)
if
parseErr
!=
nil
{
response
.
ErrorFrom
(
c
,
infraerrors
.
BadRequest
(
"INVALID_GROUP_FILTER"
,
"invalid group filter"
))
return
}
if
parsedGroupID
<
0
{
response
.
ErrorFrom
(
c
,
infraerrors
.
BadRequest
(
"INVALID_GROUP_FILTER"
,
"invalid group filter"
))
return
}
groupID
=
parsedGroupID
}
}
}
accounts
,
total
,
err
:=
h
.
adminService
.
ListAccounts
(
c
.
Request
.
Context
(),
page
,
pageSize
,
platform
,
accountType
,
status
,
search
,
groupID
)
accounts
,
total
,
err
:=
h
.
adminService
.
ListAccounts
(
c
.
Request
.
Context
(),
page
,
pageSize
,
platform
,
accountType
,
status
,
search
,
groupID
)
...
...
backend/internal/repository/account_repo.go
View file @
8027531d
...
@@ -473,7 +473,9 @@ func (r *accountRepository) ListWithFilters(ctx context.Context, params paginati
...
@@ -473,7 +473,9 @@ func (r *accountRepository) ListWithFilters(ctx context.Context, params paginati
if
search
!=
""
{
if
search
!=
""
{
q
=
q
.
Where
(
dbaccount
.
NameContainsFold
(
search
))
q
=
q
.
Where
(
dbaccount
.
NameContainsFold
(
search
))
}
}
if
groupID
>
0
{
if
groupID
==
service
.
AccountListGroupUngrouped
{
q
=
q
.
Where
(
dbaccount
.
Not
(
dbaccount
.
HasAccountGroups
()))
}
else
if
groupID
>
0
{
q
=
q
.
Where
(
dbaccount
.
HasAccountGroupsWith
(
dbaccountgroup
.
GroupIDEQ
(
groupID
)))
q
=
q
.
Where
(
dbaccount
.
HasAccountGroupsWith
(
dbaccountgroup
.
GroupIDEQ
(
groupID
)))
}
}
...
...
backend/internal/repository/account_repo_integration_test.go
View file @
8027531d
...
@@ -214,6 +214,7 @@ func (s *AccountRepoSuite) TestListWithFilters() {
...
@@ -214,6 +214,7 @@ func (s *AccountRepoSuite) TestListWithFilters() {
accType
string
accType
string
status
string
status
string
search
string
search
string
groupID
int64
wantCount
int
wantCount
int
validate
func
(
accounts
[]
service
.
Account
)
validate
func
(
accounts
[]
service
.
Account
)
}{
}{
...
@@ -265,6 +266,21 @@ func (s *AccountRepoSuite) TestListWithFilters() {
...
@@ -265,6 +266,21 @@ func (s *AccountRepoSuite) TestListWithFilters() {
s
.
Require
()
.
Contains
(
accounts
[
0
]
.
Name
,
"alpha"
)
s
.
Require
()
.
Contains
(
accounts
[
0
]
.
Name
,
"alpha"
)
},
},
},
},
{
name
:
"filter_by_ungrouped"
,
setup
:
func
(
client
*
dbent
.
Client
)
{
group
:=
mustCreateGroup
(
s
.
T
(),
client
,
&
service
.
Group
{
Name
:
"g-ungrouped"
})
grouped
:=
mustCreateAccount
(
s
.
T
(),
client
,
&
service
.
Account
{
Name
:
"grouped-account"
})
mustCreateAccount
(
s
.
T
(),
client
,
&
service
.
Account
{
Name
:
"ungrouped-account"
})
mustBindAccountToGroup
(
s
.
T
(),
client
,
grouped
.
ID
,
group
.
ID
,
1
)
},
groupID
:
service
.
AccountListGroupUngrouped
,
wantCount
:
1
,
validate
:
func
(
accounts
[]
service
.
Account
)
{
s
.
Require
()
.
Equal
(
"ungrouped-account"
,
accounts
[
0
]
.
Name
)
s
.
Require
()
.
Empty
(
accounts
[
0
]
.
GroupIDs
)
},
},
}
}
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
...
@@ -277,7 +293,7 @@ func (s *AccountRepoSuite) TestListWithFilters() {
...
@@ -277,7 +293,7 @@ func (s *AccountRepoSuite) TestListWithFilters() {
tt
.
setup
(
client
)
tt
.
setup
(
client
)
accounts
,
_
,
err
:=
repo
.
ListWithFilters
(
ctx
,
pagination
.
PaginationParams
{
Page
:
1
,
PageSize
:
10
},
tt
.
platform
,
tt
.
accType
,
tt
.
status
,
tt
.
search
,
0
)
accounts
,
_
,
err
:=
repo
.
ListWithFilters
(
ctx
,
pagination
.
PaginationParams
{
Page
:
1
,
PageSize
:
10
},
tt
.
platform
,
tt
.
accType
,
tt
.
status
,
tt
.
search
,
tt
.
groupID
)
s
.
Require
()
.
NoError
(
err
)
s
.
Require
()
.
NoError
(
err
)
s
.
Require
()
.
Len
(
accounts
,
tt
.
wantCount
)
s
.
Require
()
.
Len
(
accounts
,
tt
.
wantCount
)
if
tt
.
validate
!=
nil
{
if
tt
.
validate
!=
nil
{
...
...
backend/internal/service/account_service.go
View file @
8027531d
...
@@ -14,6 +14,8 @@ var (
...
@@ -14,6 +14,8 @@ var (
ErrAccountNilInput
=
infraerrors
.
BadRequest
(
"ACCOUNT_NIL_INPUT"
,
"account input cannot be nil"
)
ErrAccountNilInput
=
infraerrors
.
BadRequest
(
"ACCOUNT_NIL_INPUT"
,
"account input cannot be nil"
)
)
)
const
AccountListGroupUngrouped
int64
=
-
1
type
AccountRepository
interface
{
type
AccountRepository
interface
{
Create
(
ctx
context
.
Context
,
account
*
Account
)
error
Create
(
ctx
context
.
Context
,
account
*
Account
)
error
GetByID
(
ctx
context
.
Context
,
id
int64
)
(
*
Account
,
error
)
GetByID
(
ctx
context
.
Context
,
id
int64
)
(
*
Account
,
error
)
...
...
frontend/src/api/admin/accounts.ts
View file @
8027531d
...
@@ -66,6 +66,7 @@ export async function listWithEtag(
...
@@ -66,6 +66,7 @@ export async function listWithEtag(
platform
?:
string
platform
?:
string
type
?:
string
type
?:
string
status
?:
string
status
?:
string
group
?:
string
search
?:
string
search
?:
string
lite
?:
string
lite
?:
string
},
},
...
...
frontend/src/components/admin/account/AccountTableFilters.vue
View file @
8027531d
...
@@ -26,5 +26,9 @@ const updateGroup = (value: string | number | boolean | null) => { emit('update:
...
@@ -26,5 +26,9 @@ const updateGroup = (value: string | number | boolean | null) => { emit('update:
const
pOpts
=
computed
(()
=>
[{
value
:
''
,
label
:
t
(
'
admin.accounts.allPlatforms
'
)
},
{
value
:
'
anthropic
'
,
label
:
'
Anthropic
'
},
{
value
:
'
openai
'
,
label
:
'
OpenAI
'
},
{
value
:
'
gemini
'
,
label
:
'
Gemini
'
},
{
value
:
'
antigravity
'
,
label
:
'
Antigravity
'
},
{
value
:
'
sora
'
,
label
:
'
Sora
'
}])
const
pOpts
=
computed
(()
=>
[{
value
:
''
,
label
:
t
(
'
admin.accounts.allPlatforms
'
)
},
{
value
:
'
anthropic
'
,
label
:
'
Anthropic
'
},
{
value
:
'
openai
'
,
label
:
'
OpenAI
'
},
{
value
:
'
gemini
'
,
label
:
'
Gemini
'
},
{
value
:
'
antigravity
'
,
label
:
'
Antigravity
'
},
{
value
:
'
sora
'
,
label
:
'
Sora
'
}])
const
tOpts
=
computed
(()
=>
[{
value
:
''
,
label
:
t
(
'
admin.accounts.allTypes
'
)
},
{
value
:
'
oauth
'
,
label
:
t
(
'
admin.accounts.oauthType
'
)
},
{
value
:
'
setup-token
'
,
label
:
t
(
'
admin.accounts.setupToken
'
)
},
{
value
:
'
apikey
'
,
label
:
t
(
'
admin.accounts.apiKey
'
)
},
{
value
:
'
bedrock
'
,
label
:
'
AWS Bedrock
'
}])
const
tOpts
=
computed
(()
=>
[{
value
:
''
,
label
:
t
(
'
admin.accounts.allTypes
'
)
},
{
value
:
'
oauth
'
,
label
:
t
(
'
admin.accounts.oauthType
'
)
},
{
value
:
'
setup-token
'
,
label
:
t
(
'
admin.accounts.setupToken
'
)
},
{
value
:
'
apikey
'
,
label
:
t
(
'
admin.accounts.apiKey
'
)
},
{
value
:
'
bedrock
'
,
label
:
'
AWS Bedrock
'
}])
const
sOpts
=
computed
(()
=>
[{
value
:
''
,
label
:
t
(
'
admin.accounts.allStatus
'
)
},
{
value
:
'
active
'
,
label
:
t
(
'
admin.accounts.status.active
'
)
},
{
value
:
'
inactive
'
,
label
:
t
(
'
admin.accounts.status.inactive
'
)
},
{
value
:
'
error
'
,
label
:
t
(
'
admin.accounts.status.error
'
)
},
{
value
:
'
rate_limited
'
,
label
:
t
(
'
admin.accounts.status.rateLimited
'
)
},
{
value
:
'
temp_unschedulable
'
,
label
:
t
(
'
admin.accounts.status.tempUnschedulable
'
)
}])
const
sOpts
=
computed
(()
=>
[{
value
:
''
,
label
:
t
(
'
admin.accounts.allStatus
'
)
},
{
value
:
'
active
'
,
label
:
t
(
'
admin.accounts.status.active
'
)
},
{
value
:
'
inactive
'
,
label
:
t
(
'
admin.accounts.status.inactive
'
)
},
{
value
:
'
error
'
,
label
:
t
(
'
admin.accounts.status.error
'
)
},
{
value
:
'
rate_limited
'
,
label
:
t
(
'
admin.accounts.status.rateLimited
'
)
},
{
value
:
'
temp_unschedulable
'
,
label
:
t
(
'
admin.accounts.status.tempUnschedulable
'
)
}])
const
gOpts
=
computed
(()
=>
[{
value
:
''
,
label
:
t
(
'
admin.accounts.allGroups
'
)
},
...(
props
.
groups
||
[]).
map
(
g
=>
({
value
:
String
(
g
.
id
),
label
:
g
.
name
}))])
const
gOpts
=
computed
(()
=>
[
{
value
:
''
,
label
:
t
(
'
admin.accounts.allGroups
'
)
},
{
value
:
'
ungrouped
'
,
label
:
t
(
'
admin.accounts.ungroupedGroup
'
)
},
...(
props
.
groups
||
[]).
map
(
g
=>
({
value
:
String
(
g
.
id
),
label
:
g
.
name
}))
])
</
script
>
</
script
>
frontend/src/i18n/locales/en.ts
View file @
8027531d
...
@@ -1883,6 +1883,7 @@ export default {
...
@@ -1883,6 +1883,7 @@ export default {
allTypes
:
'
All Types
'
,
allTypes
:
'
All Types
'
,
allStatus
:
'
All Status
'
,
allStatus
:
'
All Status
'
,
allGroups
:
'
All Groups
'
,
allGroups
:
'
All Groups
'
,
ungroupedGroup
:
'
Ungrouped
'
,
oauthType
:
'
OAuth
'
,
oauthType
:
'
OAuth
'
,
setupToken
:
'
Setup Token
'
,
setupToken
:
'
Setup Token
'
,
apiKey
:
'
API Key
'
,
apiKey
:
'
API Key
'
,
...
...
frontend/src/i18n/locales/zh.ts
View file @
8027531d
...
@@ -1965,6 +1965,7 @@ export default {
...
@@ -1965,6 +1965,7 @@ export default {
allTypes
:
'
全部类型
'
,
allTypes
:
'
全部类型
'
,
allStatus
:
'
全部状态
'
,
allStatus
:
'
全部状态
'
,
allGroups
:
'
全部分组
'
,
allGroups
:
'
全部分组
'
,
ungroupedGroup
:
'
未分配分组
'
,
oauthType
:
'
OAuth
'
,
oauthType
:
'
OAuth
'
,
// Schedulable toggle
// Schedulable toggle
schedulable
:
'
参与调度
'
,
schedulable
:
'
参与调度
'
,
...
...
frontend/src/views/admin/AccountsView.vue
View file @
8027531d
...
@@ -758,6 +758,7 @@ const refreshAccountsIncrementally = async () => {
...
@@ -758,6 +758,7 @@ const refreshAccountsIncrementally = async () => {
platform
?:
string
platform
?:
string
type
?:
string
type
?:
string
status
?:
string
status
?:
string
group
?:
string
search
?:
string
search
?:
string
}
,
}
,
...
...
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