UI: „Einloggen als" je Reseller (Portal-Admin)
ResellersView: pro Reseller ein „Einloggen als" → impersoniert den Reseller-Admin (login + ROLE_RESELLER_ADMIN der zugehörigen Firma) → Wechsel in Reseller-Kontext. Eigene Plattform-Org (nur Plattform-Admins) bekommt korrekt keinen Button. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
44661d9b02
commit
7af4eafcad
@ -1,7 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { list, remove } from '@/api/resources'
|
||||
import client from '@/api/client'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import Modal from '@/components/Modal.vue'
|
||||
|
||||
interface Reseller {
|
||||
@ -10,10 +12,34 @@ interface Reseller {
|
||||
platformPlan: string | null; companies: string[]
|
||||
}
|
||||
interface Plan { '@id': string; id: string; name: string }
|
||||
interface Company { '@id': string; reseller: string | null }
|
||||
interface Employee { '@id': string; id: string; company: string; roles: string[]; login: boolean }
|
||||
|
||||
const auth = useAuthStore()
|
||||
const router = useRouter()
|
||||
const resellers = ref<Reseller[]>([])
|
||||
const plans = ref<Plan[]>([])
|
||||
const companies = ref<Company[]>([])
|
||||
const employees = ref<Employee[]>([])
|
||||
const busy = ref('')
|
||||
const loading = ref(true)
|
||||
|
||||
// Firma-IRI → Reseller-IRI, um den Reseller-Admin je Reseller zu finden
|
||||
const companyReseller = computed(() => Object.fromEntries(companies.value.map((c) => [c['@id'], c.reseller])))
|
||||
function resellerAdmin(r: Reseller): Employee | undefined {
|
||||
return employees.value.find((e) =>
|
||||
e.login && e.roles.includes('ROLE_RESELLER_ADMIN') && companyReseller.value[e.company] === r['@id'],
|
||||
)
|
||||
}
|
||||
async function loginAs(employeeId: string) {
|
||||
busy.value = employeeId
|
||||
try {
|
||||
await auth.impersonate(employeeId)
|
||||
router.push('/app')
|
||||
} catch {
|
||||
alert('Einloggen als … fehlgeschlagen.')
|
||||
} finally { busy.value = '' }
|
||||
}
|
||||
const showForm = ref(false)
|
||||
const saving = ref(false)
|
||||
const error = ref('')
|
||||
@ -27,9 +53,11 @@ function slugify(s: string) {
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
;[resellers.value, plans.value] = await Promise.all([
|
||||
;[resellers.value, plans.value, companies.value, employees.value] = await Promise.all([
|
||||
list<Reseller>('resellers').then((r) => r.member),
|
||||
list<Plan>('platform_plans').then((r) => r.member).catch(() => []),
|
||||
list<Company>('companies').then((r) => r.member).catch(() => []),
|
||||
list<Employee>('employees').then((r) => r.member).catch(() => []),
|
||||
])
|
||||
loading.value = false
|
||||
}
|
||||
@ -78,7 +106,11 @@ onMounted(load)
|
||||
<td>{{ r.platformPlan ? (planMap[r.platformPlan] ?? '—') : '—' }}</td>
|
||||
<td>{{ r.companies?.length ?? 0 }}</td>
|
||||
<td><span class="badge" :class="r.status === 'active' ? 'badge-active' : 'badge-inactive'">{{ r.status }}</span></td>
|
||||
<td class="right"><button class="btn btn-ghost btn-sm" @click="del(r)">Löschen</button></td>
|
||||
<td class="right">
|
||||
<button v-if="resellerAdmin(r)" class="btn btn-soft btn-sm" :disabled="busy !== ''"
|
||||
@click="loginAs(resellerAdmin(r)!.id)">Einloggen als</button>
|
||||
<button class="btn btn-ghost btn-sm" @click="del(r)">Löschen</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user