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
dd8d5e2c
Commit
dd8d5e2c
authored
Jan 20, 2026
by
墨颜
Browse files
mod(frontend): 订阅分组下拉显示备注
- 订阅管理/分配订阅:下拉项展示分组备注 - 兑换码/订阅类型:下拉项展示分组备注 - 复用 GroupOptionItem/GroupBadge 保持一致体验
parent
c8fb9ef3
Changes
2
Hide whitespace changes
Inline
Side-by-side
frontend/src/views/admin/RedeemView.vue
View file @
dd8d5e2c
...
@@ -238,7 +238,30 @@
...
@@ -238,7 +238,30 @@
v
-
model
=
"
generateForm.group_id
"
v
-
model
=
"
generateForm.group_id
"
:
options
=
"
subscriptionGroupOptions
"
:
options
=
"
subscriptionGroupOptions
"
:
placeholder
=
"
t('admin.redeem.selectGroupPlaceholder')
"
:
placeholder
=
"
t('admin.redeem.selectGroupPlaceholder')
"
/>
>
<
template
#
selected
=
"
{ option
}
"
>
<
GroupBadge
v
-
if
=
"
option
"
:
name
=
"
(option as unknown as GroupOption).label
"
:
platform
=
"
(option as unknown as GroupOption).platform
"
:
subscription
-
type
=
"
(option as unknown as GroupOption).subscriptionType
"
:
rate
-
multiplier
=
"
(option as unknown as GroupOption).rate
"
/>
<
span
v
-
else
class
=
"
text-gray-400
"
>
{{
t
(
'
admin.redeem.selectGroupPlaceholder
'
)
}}
<
/span
>
<
/template
>
<
template
#
option
=
"
{ option, selected
}
"
>
<
GroupOptionItem
:
name
=
"
(option as unknown as GroupOption).label
"
:
platform
=
"
(option as unknown as GroupOption).platform
"
:
subscription
-
type
=
"
(option as unknown as GroupOption).subscriptionType
"
:
rate
-
multiplier
=
"
(option as unknown as GroupOption).rate
"
:
description
=
"
(option as unknown as GroupOption).description
"
:
selected
=
"
selected
"
/>
<
/template
>
<
/Select
>
<
/div
>
<
/div
>
<
div
>
<
div
>
<
label
class
=
"
input-label
"
>
{{
t
(
'
admin.redeem.validityDays
'
)
}}
<
/label
>
<
label
class
=
"
input-label
"
>
{{
t
(
'
admin.redeem.validityDays
'
)
}}
<
/label
>
...
@@ -370,7 +393,7 @@ import { useAppStore } from '@/stores/app'
...
@@ -370,7 +393,7 @@ import { useAppStore } from '@/stores/app'
import
{
useClipboard
}
from
'
@/composables/useClipboard
'
import
{
useClipboard
}
from
'
@/composables/useClipboard
'
import
{
adminAPI
}
from
'
@/api/admin
'
import
{
adminAPI
}
from
'
@/api/admin
'
import
{
formatDateTime
}
from
'
@/utils/format
'
import
{
formatDateTime
}
from
'
@/utils/format
'
import
type
{
RedeemCode
,
RedeemCodeType
,
Group
}
from
'
@/types
'
import
type
{
RedeemCode
,
RedeemCodeType
,
Group
,
GroupPlatform
,
SubscriptionType
}
from
'
@/types
'
import
type
{
Column
}
from
'
@/components/common/types
'
import
type
{
Column
}
from
'
@/components/common/types
'
import
AppLayout
from
'
@/components/layout/AppLayout.vue
'
import
AppLayout
from
'
@/components/layout/AppLayout.vue
'
import
TablePageLayout
from
'
@/components/layout/TablePageLayout.vue
'
import
TablePageLayout
from
'
@/components/layout/TablePageLayout.vue
'
...
@@ -378,12 +401,23 @@ import DataTable from '@/components/common/DataTable.vue'
...
@@ -378,12 +401,23 @@ import DataTable from '@/components/common/DataTable.vue'
import
Pagination
from
'
@/components/common/Pagination.vue
'
import
Pagination
from
'
@/components/common/Pagination.vue
'
import
ConfirmDialog
from
'
@/components/common/ConfirmDialog.vue
'
import
ConfirmDialog
from
'
@/components/common/ConfirmDialog.vue
'
import
Select
from
'
@/components/common/Select.vue
'
import
Select
from
'
@/components/common/Select.vue
'
import
GroupBadge
from
'
@/components/common/GroupBadge.vue
'
import
GroupOptionItem
from
'
@/components/common/GroupOptionItem.vue
'
import
Icon
from
'
@/components/icons/Icon.vue
'
import
Icon
from
'
@/components/icons/Icon.vue
'
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
const
appStore
=
useAppStore
()
const
appStore
=
useAppStore
()
const
{
copyToClipboard
:
clipboardCopy
}
=
useClipboard
()
const
{
copyToClipboard
:
clipboardCopy
}
=
useClipboard
()
interface
GroupOption
{
value
:
number
label
:
string
description
:
string
|
null
platform
:
GroupPlatform
subscriptionType
:
SubscriptionType
rate
:
number
}
const
showGenerateDialog
=
ref
(
false
)
const
showGenerateDialog
=
ref
(
false
)
const
showResultDialog
=
ref
(
false
)
const
showResultDialog
=
ref
(
false
)
const
generatedCodes
=
ref
<
RedeemCode
[]
>
([])
const
generatedCodes
=
ref
<
RedeemCode
[]
>
([])
...
@@ -395,7 +429,11 @@ const subscriptionGroupOptions = computed(() => {
...
@@ -395,7 +429,11 @@ const subscriptionGroupOptions = computed(() => {
.
filter
((
g
)
=>
g
.
subscription_type
===
'
subscription
'
)
.
filter
((
g
)
=>
g
.
subscription_type
===
'
subscription
'
)
.
map
((
g
)
=>
({
.
map
((
g
)
=>
({
value
:
g
.
id
,
value
:
g
.
id
,
label
:
g
.
name
label
:
g
.
name
,
description
:
g
.
description
,
platform
:
g
.
platform
,
subscriptionType
:
g
.
subscription_type
,
rate
:
g
.
rate_multiplier
}
))
}
))
}
)
}
)
...
...
frontend/src/views/admin/SubscriptionsView.vue
View file @
dd8d5e2c
...
@@ -466,7 +466,28 @@
...
@@ -466,7 +466,28 @@
v
-
model
=
"
assignForm.group_id
"
v
-
model
=
"
assignForm.group_id
"
:
options
=
"
subscriptionGroupOptions
"
:
options
=
"
subscriptionGroupOptions
"
:
placeholder
=
"
t('admin.subscriptions.selectGroup')
"
:
placeholder
=
"
t('admin.subscriptions.selectGroup')
"
/>
>
<
template
#
selected
=
"
{ option
}
"
>
<
GroupBadge
v
-
if
=
"
option
"
:
name
=
"
(option as unknown as GroupOption).label
"
:
platform
=
"
(option as unknown as GroupOption).platform
"
:
subscription
-
type
=
"
(option as unknown as GroupOption).subscriptionType
"
:
rate
-
multiplier
=
"
(option as unknown as GroupOption).rate
"
/>
<
span
v
-
else
class
=
"
text-gray-400
"
>
{{
t
(
'
admin.subscriptions.selectGroup
'
)
}}
<
/span
>
<
/template
>
<
template
#
option
=
"
{ option, selected
}
"
>
<
GroupOptionItem
:
name
=
"
(option as unknown as GroupOption).label
"
:
platform
=
"
(option as unknown as GroupOption).platform
"
:
subscription
-
type
=
"
(option as unknown as GroupOption).subscriptionType
"
:
rate
-
multiplier
=
"
(option as unknown as GroupOption).rate
"
:
description
=
"
(option as unknown as GroupOption).description
"
:
selected
=
"
selected
"
/>
<
/template
>
<
/Select
>
<
p
class
=
"
input-hint
"
>
{{
t
(
'
admin.subscriptions.groupHint
'
)
}}
<
/p
>
<
p
class
=
"
input-hint
"
>
{{
t
(
'
admin.subscriptions.groupHint
'
)
}}
<
/p
>
<
/div
>
<
/div
>
<
div
>
<
div
>
...
@@ -584,7 +605,7 @@ import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
...
@@ -584,7 +605,7 @@ import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import
{
useI18n
}
from
'
vue-i18n
'
import
{
useI18n
}
from
'
vue-i18n
'
import
{
useAppStore
}
from
'
@/stores/app
'
import
{
useAppStore
}
from
'
@/stores/app
'
import
{
adminAPI
}
from
'
@/api/admin
'
import
{
adminAPI
}
from
'
@/api/admin
'
import
type
{
UserSubscription
,
Group
}
from
'
@/types
'
import
type
{
UserSubscription
,
Group
,
GroupPlatform
,
SubscriptionType
}
from
'
@/types
'
import
type
{
SimpleUser
}
from
'
@/api/admin/usage
'
import
type
{
SimpleUser
}
from
'
@/api/admin/usage
'
import
type
{
Column
}
from
'
@/components/common/types
'
import
type
{
Column
}
from
'
@/components/common/types
'
import
{
formatDateOnly
}
from
'
@/utils/format
'
import
{
formatDateOnly
}
from
'
@/utils/format
'
...
@@ -597,11 +618,21 @@ import ConfirmDialog from '@/components/common/ConfirmDialog.vue'
...
@@ -597,11 +618,21 @@ import ConfirmDialog from '@/components/common/ConfirmDialog.vue'
import
EmptyState
from
'
@/components/common/EmptyState.vue
'
import
EmptyState
from
'
@/components/common/EmptyState.vue
'
import
Select
from
'
@/components/common/Select.vue
'
import
Select
from
'
@/components/common/Select.vue
'
import
GroupBadge
from
'
@/components/common/GroupBadge.vue
'
import
GroupBadge
from
'
@/components/common/GroupBadge.vue
'
import
GroupOptionItem
from
'
@/components/common/GroupOptionItem.vue
'
import
Icon
from
'
@/components/icons/Icon.vue
'
import
Icon
from
'
@/components/icons/Icon.vue
'
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
const
appStore
=
useAppStore
()
const
appStore
=
useAppStore
()
interface
GroupOption
{
value
:
number
label
:
string
description
:
string
|
null
platform
:
GroupPlatform
subscriptionType
:
SubscriptionType
rate
:
number
}
// User column display mode: 'email' or 'username'
// User column display mode: 'email' or 'username'
const
userColumnMode
=
ref
<
'
email
'
|
'
username
'
>
(
'
email
'
)
const
userColumnMode
=
ref
<
'
email
'
|
'
username
'
>
(
'
email
'
)
const
USER_COLUMN_MODE_KEY
=
'
subscription-user-column-mode
'
const
USER_COLUMN_MODE_KEY
=
'
subscription-user-column-mode
'
...
@@ -777,7 +808,14 @@ const groupOptions = computed(() => [
...
@@ -777,7 +808,14 @@ const groupOptions = computed(() => [
const
subscriptionGroupOptions
=
computed
(()
=>
const
subscriptionGroupOptions
=
computed
(()
=>
groups
.
value
groups
.
value
.
filter
((
g
)
=>
g
.
subscription_type
===
'
subscription
'
&&
g
.
status
===
'
active
'
)
.
filter
((
g
)
=>
g
.
subscription_type
===
'
subscription
'
&&
g
.
status
===
'
active
'
)
.
map
((
g
)
=>
({
value
:
g
.
id
,
label
:
g
.
name
}
))
.
map
((
g
)
=>
({
value
:
g
.
id
,
label
:
g
.
name
,
description
:
g
.
description
,
platform
:
g
.
platform
,
subscriptionType
:
g
.
subscription_type
,
rate
:
g
.
rate_multiplier
}
))
)
)
const
applyFilters
=
()
=>
{
const
applyFilters
=
()
=>
{
...
...
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