feat: Admin-Bereich im Kundenportal (Ticketsystem-Login, Projektsuche, Kundenverwaltung)
- Login: Appwrite-User mit Label 'admin' (Ticketsystem-Mitarbeiter) bekommen eine Admin-Session und landen auf /admin.html - Admin-Dashboard: Statistik-Uebersicht, Projektsuche ueber alle Projekte (inkl. Preview-/Gitea-Links, Vorschau ohne Kunden-Login), Kundenliste mit Portal-Status, letztem Login und Projektanzahl - Kundennummer (code) direkt im Admin-Bereich pflegbar - 'Als Kunde ansehen': Admin sieht das Portal exakt wie der Kunde (Banner mit Rueckweg zur Admin-Uebersicht) - Kunden-Dashboard: neue Bereiche 'Meine Rechnungen' (InvoiceNinja inkl. Link ins Rechnungsportal) und 'Was wurde gemacht' (Tickets + Worksheets aus dem Ticketsystem, ohne interne Akquise-Tickets); Kundennummer im Header - Admin-API /api/portal-admin/* (Session-basiert), Kunden-API /api/invoices und /api/activity - appwriteClient: uebrig gebliebene Debug-Instrumentierung entfernt Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
57
server/services/customerActivity.js
Normal file
57
server/services/customerActivity.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { config } from '../config.js'
|
||||
import { listDocuments, Query } from './appwriteAdmin.js'
|
||||
|
||||
/**
|
||||
* Tickets + zugehoerige Worksheets eines Kunden ("was wurde gemacht").
|
||||
* excludeTypes: Ticket-Typen, die der Kunde nicht sehen soll (z. B. Akquise).
|
||||
*/
|
||||
export async function getCustomerActivity(customerId, { ticketLimit = 25, excludeTypes = [] } = {}) {
|
||||
if (!customerId) return []
|
||||
|
||||
let workorders = await listDocuments(config.collections.workorders, [
|
||||
Query.equal('customerId', customerId),
|
||||
Query.orderDesc('$createdAt'),
|
||||
Query.limit(ticketLimit),
|
||||
])
|
||||
|
||||
if (excludeTypes.length) {
|
||||
const blocked = new Set(excludeTypes.map((t) => t.toLowerCase()))
|
||||
workorders = workorders.filter((w) => !blocked.has(String(w.type || '').toLowerCase()))
|
||||
}
|
||||
|
||||
const ids = workorders.map((w) => w.$id)
|
||||
let worksheets = []
|
||||
if (ids.length) {
|
||||
worksheets = await listDocuments(config.collections.worksheets, [
|
||||
Query.equal('workorderId', ids),
|
||||
Query.orderDesc('$createdAt'),
|
||||
Query.limit(300),
|
||||
]).catch(() => [])
|
||||
}
|
||||
|
||||
const sheetsByWorkorder = {}
|
||||
for (const ws of worksheets) {
|
||||
if (ws.isComment) continue
|
||||
const list = (sheetsByWorkorder[ws.workorderId] ||= [])
|
||||
list.push({
|
||||
wsid: ws.wsid || '',
|
||||
employeeName: ws.employeeName || ws.employeeShort || '',
|
||||
serviceType: ws.serviceType || '',
|
||||
newStatus: ws.newStatus || '',
|
||||
totalTime: ws.totalTime || '',
|
||||
date: ws.endDate || ws.startDate || '',
|
||||
details: ws.details || '',
|
||||
createdAt: ws.createdAt || ws.$createdAt || '',
|
||||
})
|
||||
}
|
||||
|
||||
return workorders.map((w) => ({
|
||||
id: w.$id,
|
||||
woid: w.woid || '',
|
||||
topic: w.topic || w.title || '',
|
||||
status: w.status || '',
|
||||
type: w.type || '',
|
||||
createdAt: w.createdAt || w.$createdAt || '',
|
||||
worksheets: (sheetsByWorkorder[w.$id] || []).slice(0, 20),
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user