feat(admin): 商品管理支持多选皮肤筛选且要求包含所选全部皮肤

- 后端过滤:将 AdminListQuery.SkinName 筛选逻辑对齐前台,由 OR(交集) 改为 AND(全包含),选多款皮肤时账号必须同时包含所选的全部皮肤
- 前端交互:AdminListingsView 皮肤筛选支持多选交互,点击具体皮肤支持多选高亮,底部提供已选数量提示、清空与确定操作,外层按钮智能展示已选皮肤摘要
- 样式增强:补充管理后台皮肤筛选弹层底部的清空/确定操作栏样式
- 验证方式:新增并运行后端 TestFilterAdminListingsByMultipleSkinsRequiresAll 单元测试,运行全量 ./scripts/check.sh 门禁全绿通过
This commit is contained in:
yml2213
2026-10-10 17:14:47 +08:00
parent a93c76bcf6
commit 9d5d35c7d4
4 changed files with 121 additions and 18 deletions
@@ -33,12 +33,11 @@ func matchesAdminAssetQuery(item ListingDTO, query AdminListQuery) bool {
return false
}
if len(query.SkinName) > 0 {
if len(query.SkinGroup) > 0 {
return skinGroupsContainAny(item.AssetSummary, query.SkinGroup, query.SkinName)
// 皮肤筛选:多选时要求账号必须包含所有选中项(AND),与前台首页一致
if !containsAll(query.SkinName, skinNamesFromSummary(item.AssetSummary)) {
return false
}
return intersects(query.SkinName, skinNamesFromSummary(item.AssetSummary))
}
if len(query.SkinGroup) > 0 {
} else if len(query.SkinGroup) > 0 {
return skinGroupsHaveAny(item.AssetSummary, query.SkinGroup)
}
return true
@@ -98,6 +98,37 @@ func TestFilterAdminListingsBySkinGroupOnly(t *testing.T) {
}
}
func TestFilterAdminListingsByMultipleSkinsRequiresAll(t *testing.T) {
items := []ListingDTO{
{
ID: 1,
AssetSummary: map[string]any{
"skin_groups": map[string]any{
"melee": []any{"坠星者", "暗星"},
"weapon": []any{"M7棱镜攻势S2"},
},
},
},
{
ID: 2,
AssetSummary: map[string]any{
"skin_groups": map[string]any{
"melee": []any{"坠星者"},
},
},
},
}
// 选了 "坠星者" 和 "暗星",只有同时具备两者的 ID=1 才能被筛选出,ID=2 仅有坠星者应被排除
filtered := filterAdminListings(items, AdminListQuery{
SkinName: []string{"坠星者", "暗星"},
})
if len(filtered) != 1 || filtered[0].ID != 1 {
t.Fatalf("expected only listing 1 having both skins, got %#v", filtered)
}
}
func TestApplyAdminListFiltersSmartRouting(t *testing.T) {
db := database.NewDryRunDB()
repo := &Repository{}