feat(admin): 小组视图「已激活」筛选改按「已有成员激活(可参赛)」口径
R90续三:与后端 getTeams 口径修正同步。
- 筛选下拉文案:已激活(全组已激活)→ 已有成员激活(可参赛)
未激活(含部分激活)→ 暂无成员激活
- 汇总行「已激活」改为「全员激活」(与「部分激活」并列,避免与新口径混淆)
- 「当前筛选后」补充全员激活 / 部分激活分布
- 说明行改解释新语义(不再解释上下两处人数差额)
- 删除失效的 teamPartialExtra;teamFilteredSummary 增补
filteredActivated / filteredPartial 的防御式读取
生产已部署并复验:线上产物与本地产物逐字节一致(sha256 4604d3f1…),
新文案全部在线上 JS 中检出、旧文案完全消失。
This commit is contained in:
@@ -222,7 +222,9 @@
|
|||||||
|
|
||||||
<!-- ===== 视图二:小组视图(R84 续六新增)===== -->
|
<!-- ===== 视图二:小组视图(R84 续六新增)===== -->
|
||||||
<!-- 需求:查看已激活/未激活小组,且必须携带小组所属学校名称。
|
<!-- 需求:查看已激活/未激活小组,且必须携带小组所属学校名称。
|
||||||
口径:小组键 = 组别 + 队伍号;激活 = 全组成员均已激活;
|
口径:小组键 = 组别 + 队伍号;
|
||||||
|
**「已激活」= 组内至少 1 名成员已激活(= 可以参赛)**,故「部分激活」组归入已激活侧
|
||||||
|
(R90 续三修正,旧口径为「全员激活」);
|
||||||
学校 = aggregation.organization_cn(同一小组多校时并列显示并标「多校」)。 -->
|
学校 = aggregation.organization_cn(同一小组多校时并列显示并标「多校」)。 -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
@@ -233,23 +235,23 @@
|
|||||||
<el-option label="教师组" value="jiaoshi" />
|
<el-option label="教师组" value="jiaoshi" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select v-model="teamActivatedFilter" placeholder="激活状态" clearable @change="onTeamFilterChange" class="filter-select">
|
<el-select v-model="teamActivatedFilter" placeholder="激活状态" clearable @change="onTeamFilterChange" class="filter-select">
|
||||||
<el-option label="已激活(全组已激活)" value="true" />
|
<el-option label="已有成员激活(可参赛)" value="true" />
|
||||||
<el-option label="未激活(含部分激活)" value="false" />
|
<el-option label="暂无成员激活" value="false" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-checkbox v-model="teamIncludeTest" class="import-test-flag" @change="onTeamFilterChange">
|
<el-checkbox v-model="teamIncludeTest" class="import-test-flag" @change="onTeamFilterChange">
|
||||||
含测试数据
|
含测试数据
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
<el-button size="small" type="info" plain :loading="teamsLoading" @click="fetchTeams">刷新</el-button>
|
<el-button size="small" type="info" plain :loading="teamsLoading" @click="fetchTeams">刷新</el-button>
|
||||||
<span class="team-summary" v-if="teamSummary">
|
<span class="team-summary" v-if="teamSummary">
|
||||||
共 {{ teamSummary.total }} 个小组 · 已激活 {{ teamSummary.activated }} · 部分激活 {{ teamSummary.partial }} · 未激活 {{ teamSummary.inactive }}
|
共 {{ teamSummary.total }} 个小组 · 全员激活 {{ teamSummary.activated }} · 部分激活 {{ teamSummary.partial }} · 未激活 {{ teamSummary.inactive }}
|
||||||
|成员 {{ teamSummary.memberActivated }}/{{ teamSummary.memberTotal }} 已激活
|
|成员 {{ teamSummary.memberActivated }}/{{ teamSummary.memberTotal }} 已激活
|
||||||
<template v-if="teamActivatedFilter !== ''">
|
<template v-if="teamActivatedFilter !== ''">
|
||||||
|<span class="team-summary-filtered">当前筛选后 {{ teamFilteredSummary.total }} 个小组 · 成员 {{ teamFilteredSummary.memberActivated }}/{{ teamFilteredSummary.memberTotal }} 已激活</span>
|
|<span class="team-summary-filtered">当前筛选后 {{ teamFilteredSummary.total }} 个小组<span v-if="teamActivatedFilter === 'true'">(全员激活 {{ teamFilteredSummary.activated }} · 部分激活 {{ teamFilteredSummary.partial }})</span> · 成员 {{ teamFilteredSummary.memberActivated }}/{{ teamFilteredSummary.memberTotal }} 已激活</span>
|
||||||
</template>
|
</template>
|
||||||
</span>
|
</span>
|
||||||
<!-- R90:解释「选手列表激活人数」与「已激活小组的成员数」不等的原因(差额=部分激活组内的已激活选手) -->
|
<!-- R90 续三:「已激活」= 小组内至少 1 名成员已完成激活(即可参赛),故「部分激活」组也一并计入 -->
|
||||||
<span class="team-summary-hint" v-if="teamActivatedFilter !== '' && teamPartialExtra > 0">
|
<span class="team-summary-hint" v-if="teamActivatedFilter === 'true' && teamFilteredSummary.partial > 0">
|
||||||
说明:「已激活小组」只统计「全员已激活」的小组;另有 {{ teamPartialExtra }} 名已激活选手所在小组尚未全员激活(部分激活),故不计入上表,但会计入「选手列表」的已激活人数。
|
说明:「已有成员激活」= 该小组至少 1 名成员已完成激活(即可参赛);其中 {{ teamFilteredSummary.partial }} 个小组为「部分激活」,组内尚有成员未激活。
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="teams" stripe v-loading="teamsLoading" class="admin-table" style="width: 100%">
|
<el-table :data="teams" stripe v-loading="teamsLoading" class="admin-table" style="width: 100%">
|
||||||
@@ -1890,20 +1892,18 @@ const teamIncludeTest = ref(false)
|
|||||||
const teamSummary = ref(null)
|
const teamSummary = ref(null)
|
||||||
|
|
||||||
// R90:双口径汇总的读取辅助(防御式——后端未同步时自动退回全量口径,不显示 undefined)
|
// R90:双口径汇总的读取辅助(防御式——后端未同步时自动退回全量口径,不显示 undefined)
|
||||||
|
// R90 续三:补 activated / partial 两项(筛选后三态分布),用于「已有成员激活」筛选下标注全员/部分激活构成
|
||||||
const teamFilteredSummary = computed(() => {
|
const teamFilteredSummary = computed(() => {
|
||||||
const s = teamSummary.value
|
const s = teamSummary.value
|
||||||
if (!s) return { total: 0, memberTotal: 0, memberActivated: 0 }
|
if (!s) return { total: 0, memberTotal: 0, memberActivated: 0, activated: 0, partial: 0 }
|
||||||
return {
|
return {
|
||||||
total: s.filteredTotal === undefined ? s.total : s.filteredTotal,
|
total: s.filteredTotal === undefined ? s.total : s.filteredTotal,
|
||||||
memberTotal: s.filteredMemberTotal === undefined ? s.memberTotal : s.filteredMemberTotal,
|
memberTotal: s.filteredMemberTotal === undefined ? s.memberTotal : s.filteredMemberTotal,
|
||||||
memberActivated: s.filteredMemberActivated === undefined ? s.memberActivated : s.filteredMemberActivated,
|
memberActivated: s.filteredMemberActivated === undefined ? s.memberActivated : s.filteredMemberActivated,
|
||||||
|
activated: s.filteredActivated === undefined ? 0 : s.filteredActivated,
|
||||||
|
partial: s.filteredPartial === undefined ? 0 : s.filteredPartial,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// 「部分激活」小组内已激活的选手数(= 选手列表激活人数 − 已激活小组成员数 的差额来源)
|
|
||||||
const teamPartialExtra = computed(() => {
|
|
||||||
const s = teamSummary.value
|
|
||||||
return s && typeof s.memberActivatedInPartial === 'number' ? s.memberActivatedInPartial : 0
|
|
||||||
})
|
|
||||||
|
|
||||||
async function fetchTeams() {
|
async function fetchTeams() {
|
||||||
teamsLoading.value = true
|
teamsLoading.value = true
|
||||||
|
|||||||
Reference in New Issue
Block a user