mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-17 12:54:40 +08:00
feat(ui): land viewers on /chat and show real role in switcher
This commit is contained in:
parent
777e2ecee2
commit
ccd86dbb80
@ -14,6 +14,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<template v-if="!collapsed">
|
<template v-if="!collapsed">
|
||||||
<span class="ws-trigger__name">{{ currentLabel }}</span>
|
<span class="ws-trigger__name">{{ currentLabel }}</span>
|
||||||
|
<span v-if="roleBadge" class="ws-trigger__role" :title="roleBadge.tooltip">{{ roleBadge.label }}</span>
|
||||||
<svg class="ws-trigger__arrow" :class="{ open }" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
|
<svg class="ws-trigger__arrow" :class="{ open }" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
|
||||||
</template>
|
</template>
|
||||||
</button>
|
</button>
|
||||||
@ -103,6 +104,25 @@ const workspaces = computed(() => store.workspaces)
|
|||||||
const currentWorkspaceId = computed(() => store.currentWorkspaceId)
|
const currentWorkspaceId = computed(() => store.currentWorkspaceId)
|
||||||
const currentLabel = computed(() => store.currentWorkspace?.name || 'Workspace')
|
const currentLabel = computed(() => store.currentWorkspace?.name || 'Workspace')
|
||||||
|
|
||||||
|
// Show the REAL memberRole — never effective — so a global admin viewing a
|
||||||
|
// workspace they have not joined sees "Global admin (non-member)" instead of
|
||||||
|
// being silently labelled as owner. See WorkspaceWithRoleVO docs.
|
||||||
|
const roleBadge = computed(() => {
|
||||||
|
const ws = store.currentWorkspace
|
||||||
|
if (!ws) return null
|
||||||
|
const real = ws.memberRole as string | null | undefined
|
||||||
|
if (ws.isGlobalAdmin) {
|
||||||
|
return {
|
||||||
|
label: t('nav.roleAdmin'),
|
||||||
|
tooltip: real
|
||||||
|
? `${t('nav.roleAdmin')} (${real})`
|
||||||
|
: `${t('nav.roleAdmin')} (non-member)`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!real) return null
|
||||||
|
return { label: real, tooltip: real }
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
store.fetchWorkspaces()
|
store.fetchWorkspaces()
|
||||||
})
|
})
|
||||||
@ -178,6 +198,18 @@ function onManage() {
|
|||||||
letter-spacing: -0.01em;
|
letter-spacing: -0.01em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ws-trigger__role {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 1px 6px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--mc-primary-bg, rgba(217, 109, 70, 0.12));
|
||||||
|
color: var(--mc-primary, #d96d46);
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
.ws-trigger__arrow {
|
.ws-trigger__arrow {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
color: var(--mc-sidebar-text, var(--mc-text-tertiary));
|
color: var(--mc-sidebar-text, var(--mc-text-tertiary));
|
||||||
|
|||||||
@ -61,9 +61,11 @@ import { reactive, ref } from 'vue'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { authApi } from '@/api/index'
|
import { authApi } from '@/api/index'
|
||||||
|
import { useWorkspaceStore } from '@/stores/useWorkspaceStore'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
const workspaceStore = useWorkspaceStore()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const showPassword = ref(false)
|
const showPassword = ref(false)
|
||||||
const errorMsg = ref('')
|
const errorMsg = ref('')
|
||||||
@ -80,7 +82,15 @@ async function handleLogin() {
|
|||||||
localStorage.setItem('userId', String(data.id || '1'))
|
localStorage.setItem('userId', String(data.id || '1'))
|
||||||
localStorage.setItem('username', data.username || form.username)
|
localStorage.setItem('username', data.username || form.username)
|
||||||
localStorage.setItem('role', data.role || 'user')
|
localStorage.setItem('role', data.role || 'user')
|
||||||
router.push('/')
|
// Resolve capabilities before deciding the landing route so a viewer
|
||||||
|
// lands on /chat (their only capability) and member+ on /dashboard.
|
||||||
|
try {
|
||||||
|
await workspaceStore.fetchWorkspaces()
|
||||||
|
} catch {
|
||||||
|
/* default-deny is fine; router guard will still steer */
|
||||||
|
}
|
||||||
|
const target = workspaceStore.can('view:dashboard') ? '/dashboard' : '/chat'
|
||||||
|
router.push(target)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
errorMsg.value = typeof e === 'string' ? e : t('login.failed')
|
errorMsg.value = typeof e === 'string' ? e : t('login.failed')
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user