fix(frontend): hide redundant card badges when section headers apply

Suppress duplicate origin, builtin, role, and org-name pills on knowledge
base, agent, and organization list cards when the visible group header or
sidebar filter already conveys the same information.
This commit is contained in:
wizardchen
2026-06-26 16:54:23 +08:00
committed by lyingbug
parent b8ce6a699c
commit 4588e95ba3
4 changed files with 94 additions and 21 deletions
+49
View File
@@ -0,0 +1,49 @@
/**
* Helpers to suppress card corner badges that repeat what a visible section
* header (Group) already communicates.
*/
export type ListCardSectionKey =
| 'pinned'
| 'mine'
| 'tenantOthers'
| 'builtin'
| 'sharedByMe'
| 'sharedEditable'
| 'sharedReadonly'
| 'created'
| 'joined'
export type ResourceOriginVariant = 'mine' | 'tenant' | 'creator' | 'space' | 'shared'
/** ResourceOriginBadge on KB / Agent cards. */
export function shouldShowResourceOriginBadge(opts: {
section: ListCardSectionKey | null
variant: ResourceOriginVariant
creatorName?: string
showSectionHeaders?: boolean
}): boolean {
if (!opts.showSectionHeaders) return true
const { section, variant, creatorName } = opts
const hasCreator = Boolean(creatorName?.trim())
if (section === 'mine' && variant === 'mine') return false
if (section === 'builtin') return false
if (section === 'tenantOthers' && variant === 'creator' && !hasCreator) return false
return true
}
/** Owner / role tag on organization cards. */
export function shouldShowOrgRelationTag(opts: {
spaceSelection: 'all' | 'created' | 'joined'
isOwner: boolean
myRole?: string
}): boolean {
if (opts.spaceSelection === 'created') return false
if (opts.spaceSelection === 'joined' && !opts.myRole) return false
if (opts.spaceSelection === 'all' && opts.isOwner) return false
if (opts.spaceSelection === 'all' && !opts.isOwner && !opts.myRole) return false
return true
}
+23 -9
View File
@@ -296,11 +296,11 @@
<img src="@/assets/img/organization-green.svg" class="org-icon" alt="" aria-hidden="true" />
<span class="org-source-text">{{ agent.org_name }}</span>
</div>
<div v-else-if="agent.is_builtin" class="builtin-badge">
<div v-else-if="showAgentBuiltinBadge(agent)" class="builtin-badge">
<t-icon name="lock-on" size="12px" />
<span>{{ $t('agent.builtin') }}</span>
</div>
<ResourceOriginBadge v-else :variant="agentOriginVariant(agent)"
<ResourceOriginBadge v-else-if="showAgentOriginBadge(agent)" :variant="agentOriginVariant(agent)"
:creator-name="(agent as any).creator_name" />
</div>
</div>
@@ -483,11 +483,11 @@
</div>
</div>
<!-- 右下角:内置 / 来源徽章(我创建 / 同租户其他成员) -->
<div v-if="agent.is_builtin" class="builtin-badge">
<div v-if="showAgentBuiltinBadge(agent)" class="builtin-badge">
<t-icon name="lock-on" size="12px" />
<span>{{ $t('agent.builtin') }}</span>
</div>
<ResourceOriginBadge v-else :variant="agentOriginVariant(agent)"
<ResourceOriginBadge v-else-if="showAgentOriginBadge(agent)" :variant="agentOriginVariant(agent)"
:creator-name="(agent as any).creator_name" />
</div>
</div>
@@ -631,11 +631,6 @@
</t-tooltip>
</div>
</div>
<!-- 右下角:空间图标+名称 -->
<div class="card-bottom-source">
<img src="@/assets/img/organization-green.svg" class="org-icon" alt="" aria-hidden="true" />
<span class="org-source-text">{{ shared.org_name }}</span>
</div>
</div>
</div>
</template>
@@ -839,6 +834,7 @@ import { useUIStore } from '@/stores/ui'
import AgentAvatar from '@/components/AgentAvatar.vue'
import ListSpaceSidebar from '@/components/ListSpaceSidebar.vue'
import ResourceOriginBadge from '@/components/ResourceOriginBadge.vue'
import { shouldShowResourceOriginBadge } from '@/utils/card-list-badge'
import { useAuthStore } from '@/stores/auth'
import { useListUrlState } from '@/composables/useListUrlState'
import { useResourcePins } from '@/composables/useResourcePins'
@@ -1347,6 +1343,24 @@ function agentOriginVariant(agent: { created_by?: string }): 'mine' | 'creator'
return isMyAgent(agent) ? 'mine' : 'creator'
}
function showAgentOriginBadge(agent: { created_by?: string; creator_name?: string }): boolean {
return shouldShowResourceOriginBadge({
section: agentSectionOf(agent),
variant: agentOriginVariant(agent),
creatorName: (agent as any).creator_name,
showSectionHeaders: showShareGroupHeaders.value,
})
}
function showAgentBuiltinBadge(agent: { is_builtin?: boolean }): boolean {
if (!agent.is_builtin) return false
return shouldShowResourceOriginBadge({
section: agentSectionOf(agent),
variant: 'mine',
showSectionHeaders: showShareGroupHeaders.value,
})
}
// 共享 agent 的可编辑/只读分组开关,与 KB 列表逻辑保持一致:仅对
// contributor / editor 中间档展示分组标题。Viewer / Admin+ 不分组。
const AGENT_EDITABLE_PERMS = new Set(['admin', 'editor'])
@@ -279,7 +279,7 @@
</t-tooltip>
</div>
</div>
<div v-if="!authStore.isLiteMode" class="bottom-right">
<div v-if="!authStore.isLiteMode && showKbOriginBadge(kb)" class="bottom-right">
<ResourceOriginBadge :variant="kbOriginVariant(kb)" :creator-name="kb.creator_name" />
</div>
</div>
@@ -504,7 +504,7 @@
</t-tooltip>
</div>
</div>
<div v-if="!authStore.isLiteMode" class="bottom-right">
<div v-if="!authStore.isLiteMode && showKbOriginBadge(kb)" class="bottom-right">
<ResourceOriginBadge :variant="kbOriginVariant(kb)" :creator-name="kb.creator_name" />
</div>
</div>
@@ -604,15 +604,6 @@
</t-tooltip>
</div>
</div>
<div class="bottom-right">
<t-tooltip :content="shared.org_name" placement="top">
<div class="org-source">
<img src="@/assets/img/organization-green.svg" class="org-source-icon" alt=""
aria-hidden="true" />
<span>{{ shared.org_name }}</span>
</div>
</t-tooltip>
</div>
</div>
</div>
</template>
@@ -783,6 +774,7 @@ import KnowledgeBaseEditorModal from './KnowledgeBaseEditorModal.vue'
import ShareKnowledgeBaseDialog from '@/components/ShareKnowledgeBaseDialog.vue'
import ListSpaceSidebar from '@/components/ListSpaceSidebar.vue'
import ResourceOriginBadge from '@/components/ResourceOriginBadge.vue'
import { shouldShowResourceOriginBadge } from '@/utils/card-list-badge'
import ContextualGuide from '@/components/ContextualGuide.vue'
import { isContextualGuideDone, markContextualGuideDone } from '@/config/contextualGuides'
import { useTenantModelReadiness } from '@/composables/useTenantModelReadiness'
@@ -1361,6 +1353,15 @@ function kbOriginVariant(kb: { creator_id?: string }): 'mine' | 'creator' {
return isMyKb(kb) ? 'mine' : 'creator'
}
function showKbOriginBadge(kb: { creator_id?: string; creator_name?: string }): boolean {
return shouldShowResourceOriginBadge({
section: kbSectionOf(kb),
variant: kbOriginVariant(kb),
creatorName: kb.creator_name,
showSectionHeaders: showShareGroupHeaders.value,
})
}
// 通过 ID 处理设置(用于全部 Tab 下的知识库)
const handleSettingsById = (id: string) => {
goSettings(id)
@@ -161,7 +161,7 @@
$t('organization.settings.pendingReview') }}</span>
</t-tooltip>
</div>
<div class="bottom-right">
<div v-if="showOrgRelationTag(org)" class="bottom-right">
<div class="relation-role-tag" :class="org.is_owner ? 'owner' : (org.my_role || '')">
<t-icon :name="org.is_owner ? 'usergroup-add' : 'usergroup'" size="14px" />
<span>{{ org.is_owner ? $t('organization.owner') : (org.my_role ?
@@ -557,6 +557,7 @@ import { useI18n } from 'vue-i18n'
import OrganizationSettingsModal from './OrganizationSettingsModal.vue'
import SpaceAvatar from '@/components/SpaceAvatar.vue'
import ListSpaceSidebar from '@/components/ListSpaceSidebar.vue'
import { shouldShowOrgRelationTag } from '@/utils/card-list-badge'
interface OrgWithUI extends Organization {
showMore?: boolean
@@ -809,6 +810,14 @@ const orgSectionCounts = computed<Record<OrgSectionKey, number>>(() => {
return c
})
function showOrgRelationTag(org: { is_owner?: boolean; my_role?: string }): boolean {
return shouldShowOrgRelationTag({
spaceSelection: spaceSelection.value,
isOwner: !!org.is_owner,
myRole: org.my_role,
})
}
const emptyStateTitle = computed(() => {
if (spaceSelection.value === 'created') return t('organization.emptyCreated')
if (spaceSelection.value === 'joined') return t('organization.emptyJoined')