fix(F006-W17.3.9): UserListView stats 与 tab 解耦 (跨 tab 全量计数一致)

用户反馈: 切 tab 时"正常/已禁用"两个统计数会变化 (全部 10/0, 正常 10/0, 已禁用 0/1)
期望: stats 是全量统计, 切 tab 不应变化

根因: enabledStats 是在 load() 内"基于当前页 10 条结果"累加, 切 tab 后数据不同, stats 跟着变

修法:
- 拆 load() → loadList() + loadStats()
- buildSearchParams(): 排除 enabled (tab) 的搜索参数 (userId/nickName/mobile/isEnterprise/enterpriseName)
- loadStats(): 并发拉 enabled=0/1 的 page=1&limit=1, 用 resp.total 当 stats (后端只 count 不返列表, 开销可忽略)
- onTabChange: 只调 loadList(), stats 不重算
- onSearch/onReset/onPageChange/onLimitChange/toggleEnabled: 调 load() (并发刷 list + stats)

效果: 三个 tab 看到的正常/已禁用计数一致 (因为跟 tab 解耦, 只跟搜索条件关联)
This commit is contained in:
Sisyphus 2026-07-07 17:14:11 +08:00
parent 5a7adb9075
commit a1336fe9b7

View File

@ -91,15 +91,24 @@ function fmtDate(ts: number | null | undefined) {
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}` return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
} }
async function load() { /**
* 构建除 enabled (tab) 外的搜索参数 (用于 stats 查询)
* stats 必须与 tab 解耦, 只反映当前搜索条件下的全量计数
*/
function buildSearchParams() {
const params: any = {}
if (query.userId) params.id = query.userId
if (query.nickName) params.nickName = query.nickName
if (query.mobile) params.mobile = query.mobile
if (query.enterpriseName) params.enterpriseName = query.enterpriseName
if (query.isEnterprise !== '') params.isEnterprise = Number(query.isEnterprise)
return params
}
async function loadList() {
loading.value = true loading.value = true
try { try {
const params: any = { page: query.page, limit: query.limit } const params: any = { page: query.page, limit: query.limit, ...buildSearchParams() }
if (query.userId) params.id = query.userId
if (query.nickName) params.nickName = query.nickName
if (query.mobile) params.mobile = query.mobile
if (query.enterpriseName) params.enterpriseName = query.enterpriseName
if (query.isEnterprise !== '') params.isEnterprise = Number(query.isEnterprise)
if (query.enabled !== '') params.enabled = Number(query.enabled) if (query.enabled !== '') params.enabled = Number(query.enabled)
const resp: any = await httpGet('/user/user/page', params) const resp: any = await httpGet('/user/user/page', params)
if (resp && Array.isArray(resp.list)) { if (resp && Array.isArray(resp.list)) {
@ -118,9 +127,6 @@ async function load() {
raw: it raw: it
})) }))
total.value = Number(resp.total || 0) total.value = Number(resp.total || 0)
// 统计 (后端 enabled 语义: 0=正常 1=禁用)
enabledStats.normal = list.value.filter(u => u.enabled === 0).length
enabledStats.disabled = list.value.filter(u => u.enabled === 1).length
} else { } else {
list.value = [] list.value = []
total.value = 0 total.value = 0
@ -134,6 +140,30 @@ async function load() {
} }
} }
/**
* 加载 stats (normal/disabled 全量计数)
* 与 tab 无关, 只跟搜索条件 (userId/nickName/mobile/isEnterprise/enterpriseName) 关联
* 通过 limit=1 + page=1 拿到 total (后端只 count 不返列表, 开销可忽略)
*/
async function loadStats() {
try {
const baseParams = buildSearchParams()
const [respNormal, respDisabled] = await Promise.all([
httpGet('/user/user/page', { ...baseParams, enabled: 0, page: 1, limit: 1 }),
httpGet('/user/user/page', { ...baseParams, enabled: 1, page: 1, limit: 1 })
])
enabledStats.normal = Number(respNormal?.total ?? 0)
enabledStats.disabled = Number(respDisabled?.total ?? 0)
} catch {
enabledStats.normal = 0
enabledStats.disabled = 0
}
}
async function load() {
await Promise.all([loadList(), loadStats()])
}
const tabItems = computed(() => [ const tabItems = computed(() => [
{ key: 'all', label: '全部', count: total.value }, { key: 'all', label: '全部', count: total.value },
{ key: 'normal', label: '正常', count: enabledStats.normal }, { key: 'normal', label: '正常', count: enabledStats.normal },
@ -146,7 +176,7 @@ function onTabChange(key: string) {
else if (key === 'normal') query.enabled = '0' else if (key === 'normal') query.enabled = '0'
else if (key === 'disabled') query.enabled = '1' else if (key === 'disabled') query.enabled = '1'
query.page = 1 query.page = 1
load() loadList() // 切 tab 只重载列表, stats 已与 tab 解耦
} }
function onPageChange(p: number) { query.page = p; load() } function onPageChange(p: number) { query.page = p; load() }