diff --git a/frontend/src/views/CompaniesView.vue b/frontend/src/views/CompaniesView.vue
index 70a1111..e75c82a 100644
--- a/frontend/src/views/CompaniesView.vue
+++ b/frontend/src/views/CompaniesView.vue
@@ -36,6 +36,10 @@ function slugify(s: string) {
function empOf(c: Company) {
return employees.value.filter((e) => e.company === c['@id'])
}
+// Nur Mitarbeiter, deren Login man übernehmen kann
+function loginable(c: Company) {
+ return empOf(c).filter((e) => e.login)
+}
function activeProfiles(c: Company) {
return empOf(c).filter((e) => e.status === 'active').length
}
@@ -137,18 +141,16 @@ onMounted(load)
|
- | Mitarbeiter | E-Mail | Telefon | Position | |
+ | Mitarbeiter | E-Mail | Position | |
- | Keine Mitarbeiter. |
-
+ | Keine einloggbaren Mitarbeiter. |
+
| {{ e.firstName }} {{ e.lastName }} |
{{ e.email || '–' }} |
- {{ e.phone || '–' }} |
{{ e.position || '–' }} |
-
- kein Login
|
diff --git a/frontend/src/views/ResellersView.vue b/frontend/src/views/ResellersView.vue
index 9b2544f..017ef70 100644
--- a/frontend/src/views/ResellersView.vue
+++ b/frontend/src/views/ResellersView.vue
@@ -13,7 +13,7 @@ interface Reseller {
}
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 }
+interface Employee { '@id': string; id: string; firstName: string; lastName: string; email: string | null; company: string; roles: string[]; login: boolean }
const auth = useAuthStore()
const router = useRouter()
@@ -24,13 +24,17 @@ const employees = ref([])
const busy = ref('')
const loading = ref(true)
-// Firma-IRI → Reseller-IRI, um den Reseller-Admin je Reseller zu finden
+const expanded = ref>({})
+function toggle(r: Reseller) { expanded.value[r.id] = !expanded.value[r.id] }
+
+// Firma-IRI → Reseller-IRI, um die einloggbaren Reseller-Admins 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) =>
+function resellerAdmins(r: Reseller): Employee[] {
+ return employees.value.filter((e) =>
e.login && e.roles.includes('ROLE_RESELLER_ADMIN') && companyReseller.value[e.company] === r['@id'],
)
}
+function resellerAdmin(r: Reseller): Employee | undefined { return resellerAdmins(r)[0] }
async function loginAs(employeeId: string) {
busy.value = employeeId
try {
@@ -96,22 +100,40 @@ onMounted(load)
- | Name | Domain | Paket | Firmen | Status | |
+ | Name | Domain | Paket | Firmen | Status | |
- | Lädt… |
- | Noch keine Reseller. |
-
- | {{ r.name }} {{ r.slug }} |
- {{ r.primaryDomain ?? '–' }} |
- {{ r.platformPlan ? (planMap[r.platformPlan] ?? '—') : '—' }} |
- {{ r.companies?.length ?? 0 }} |
- {{ r.status }} |
-
-
-
- |
-
+ | Lädt… |
+ | Noch keine Reseller. |
+
+
+ | › |
+ {{ r.name }} {{ r.slug }} |
+ {{ r.primaryDomain ?? '–' }} |
+ {{ r.platformPlan ? (planMap[r.platformPlan] ?? '—') : '—' }} |
+ {{ r.companies?.length ?? 0 }} |
+ {{ r.status }} |
+
+
+
+ |
+
+
+ |
+
+
+ | Reseller-Admin | E-Mail | |
+
+
+ | {{ a.firstName }} {{ a.lastName }} |
+ {{ a.email || '–' }} |
+ |
+
+
+
+ |
+
+
@@ -153,8 +175,19 @@ onMounted(load)
.tbl td { padding: .9rem 1.2rem; border-bottom: 1px solid #f4f4f4; }
.tbl tr:last-child td { border-bottom: none; }
.small { font-size: .8rem; }
-.right { text-align: right; }
+.right { text-align: right; white-space: nowrap; }
+.right .btn + .btn { margin-left: .4rem; }
.empty { text-align: center; color: var(--muted); padding: 2rem; }
+.w-caret { width: 28px; }
+.caret { display: inline-block; transition: transform .15s; color: var(--muted); font-size: 1.1rem; }
+.caret.open { transform: rotate(90deg); }
+.rrow { cursor: pointer; }
+.rrow:hover { background: #fafafa; }
+.orange { color: var(--psc-orange-dark); }
+.subrow > td { background: #fbfbfb; padding: 0 1.2rem 1rem !important; }
+.subtbl { width: 100%; border-collapse: collapse; }
+.subtbl th { text-align: left; font-size: .68rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); padding: .6rem .7rem; }
+.subtbl td { padding: .55rem .7rem; border-top: 1px solid #f0f0f0; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; }
.divider { font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 700; margin: .4rem 0 .8rem; padding-top: .8rem; border-top: 1px solid var(--line); }
.actions { display: flex; justify-content: flex-end; gap: .6rem; margin-top: 1rem; }
|