增加用户免押额度筛选
This commit is contained in:
@@ -34,8 +34,9 @@ type DepositFreeQuotaRequest struct {
|
|||||||
|
|
||||||
// ListQuery 用户列表筛选条件。Keyword 同时匹配手机号/昵称(模糊)与用户 ID(精确)。
|
// ListQuery 用户列表筛选条件。Keyword 同时匹配手机号/昵称(模糊)与用户 ID(精确)。
|
||||||
type ListQuery struct {
|
type ListQuery struct {
|
||||||
Keyword string
|
Keyword string
|
||||||
Status string
|
Status string
|
||||||
|
HasDepositFreeQuota bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaginatedResult struct {
|
type PaginatedResult struct {
|
||||||
|
|||||||
@@ -38,8 +38,9 @@ func parsePagination(c *gin.Context) (int, int) {
|
|||||||
func (h *Handler) List(c *gin.Context) {
|
func (h *Handler) List(c *gin.Context) {
|
||||||
page, pageSize := parsePagination(c)
|
page, pageSize := parsePagination(c)
|
||||||
query := ListQuery{
|
query := ListQuery{
|
||||||
Keyword: strings.TrimSpace(c.Query("keyword")),
|
Keyword: strings.TrimSpace(c.Query("keyword")),
|
||||||
Status: strings.TrimSpace(c.Query("status")),
|
Status: strings.TrimSpace(c.Query("status")),
|
||||||
|
HasDepositFreeQuota: parseBoolQuery(c.Query("has_deposit_free_quota")),
|
||||||
}
|
}
|
||||||
result, err := h.service.List(c.Request.Context(), page, pageSize, query)
|
result, err := h.service.List(c.Request.Context(), page, pageSize, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -49,6 +50,15 @@ func (h *Handler) List(c *gin.Context) {
|
|||||||
response.OK(c, result)
|
response.OK(c, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseBoolQuery(value string) bool {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||||
|
case "1", "true", "yes", "on":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) Freeze(c *gin.Context) {
|
func (h *Handler) Freeze(c *gin.Context) {
|
||||||
adminID, ok := currentAdminID(c)
|
adminID, ok := currentAdminID(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ func applyUserFilter(tx *gorm.DB, query ListQuery) *gorm.DB {
|
|||||||
if query.Status != "" {
|
if query.Status != "" {
|
||||||
tx = tx.Where("u.status = ?", query.Status)
|
tx = tx.Where("u.status = ?", query.Status)
|
||||||
}
|
}
|
||||||
|
if query.HasDepositFreeQuota {
|
||||||
|
tx = tx.Where("u.deposit_free_quota_cent > 0")
|
||||||
|
}
|
||||||
if keyword := strings.TrimSpace(query.Keyword); keyword != "" {
|
if keyword := strings.TrimSpace(query.Keyword); keyword != "" {
|
||||||
like := "%" + keyword + "%"
|
like := "%" + keyword + "%"
|
||||||
// 关键词为纯数字时一并按用户 ID 精确匹配
|
// 关键词为纯数字时一并按用户 ID 精确匹配
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
package adminuser
|
package adminuser
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gorm.io/driver/sqlite"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
func TestDepositFreeQuotaAmountCent(t *testing.T) {
|
func TestDepositFreeQuotaAmountCent(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -28,3 +34,45 @@ func TestDepositFreeQuotaAmountCent(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseBoolQuery(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "true 开启", value: "true", want: true},
|
||||||
|
{name: "数字 1 开启", value: "1", want: true},
|
||||||
|
{name: "on 开启", value: "on", want: true},
|
||||||
|
{name: "空值关闭", value: "", want: false},
|
||||||
|
{name: "false 关闭", value: "false", want: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := parseBoolQuery(tt.value); got != tt.want {
|
||||||
|
t.Fatalf("parseBoolQuery(%q) = %v, want %v", tt.value, got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApplyUserFilterHasDepositFreeQuota(t *testing.T) {
|
||||||
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{DryRun: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("打开测试数据库失败:%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt := applyUserFilter(db.Table("users AS u"), ListQuery{
|
||||||
|
Status: "active",
|
||||||
|
HasDepositFreeQuota: true,
|
||||||
|
}).Find(&[]struct{}{}).Statement
|
||||||
|
sql := stmt.SQL.String()
|
||||||
|
|
||||||
|
if !strings.Contains(sql, "u.deposit_free_quota_cent > 0") {
|
||||||
|
t.Fatalf("SQL 未包含免押额度过滤:%s", sql)
|
||||||
|
}
|
||||||
|
if len(stmt.Vars) != 1 || stmt.Vars[0] != "active" {
|
||||||
|
t.Fatalf("筛选变量不正确:%v", stmt.Vars)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ export interface AdminUserItem {
|
|||||||
export interface AdminUserQuery {
|
export interface AdminUserQuery {
|
||||||
keyword?: string
|
keyword?: string
|
||||||
status?: '' | UserStatus
|
status?: '' | UserStatus
|
||||||
|
has_deposit_free_quota?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchAdminUsers(page = 1, pageSize = 20, query: AdminUserQuery = {}) {
|
export async function fetchAdminUsers(page = 1, pageSize = 20, query: AdminUserQuery = {}) {
|
||||||
const params: Record<string, unknown> = { page, page_size: pageSize }
|
const params: Record<string, unknown> = { page, page_size: pageSize }
|
||||||
if (query.keyword) params.keyword = query.keyword
|
if (query.keyword) params.keyword = query.keyword
|
||||||
if (query.status) params.status = query.status
|
if (query.status) params.status = query.status
|
||||||
|
if (query.has_deposit_free_quota) params.has_deposit_free_quota = true
|
||||||
const { data } = await apiClient.get<ApiResponse<PaginatedResult<AdminUserItem>>>(
|
const { data } = await apiClient.get<ApiResponse<PaginatedResult<AdminUserItem>>>(
|
||||||
'/admin/users',
|
'/admin/users',
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const quotaAmount = ref(0)
|
|||||||
const filters = reactive<AdminUserQuery>({
|
const filters = reactive<AdminUserQuery>({
|
||||||
keyword: '',
|
keyword: '',
|
||||||
status: '',
|
status: '',
|
||||||
|
has_deposit_free_quota: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -51,6 +52,7 @@ function queryUsers() {
|
|||||||
function resetFilters() {
|
function resetFilters() {
|
||||||
filters.keyword = ''
|
filters.keyword = ''
|
||||||
filters.status = ''
|
filters.status = ''
|
||||||
|
filters.has_deposit_free_quota = false
|
||||||
queryUsers()
|
queryUsers()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +170,11 @@ function moneyCent(value: number | string | undefined) {
|
|||||||
<el-option label="已禁用" value="disabled" />
|
<el-option label="已禁用" value="disabled" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="免押额度">
|
||||||
|
<el-checkbox v-model="filters.has_deposit_free_quota" @change="queryUsers">
|
||||||
|
仅看有额度
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" :icon="Search" :loading="loading" @click="queryUsers"
|
<el-button type="primary" :icon="Search" :loading="loading" @click="queryUsers"
|
||||||
>查询</el-button
|
>查询</el-button
|
||||||
|
|||||||
Reference in New Issue
Block a user