Ohjeet-moduuli: Confluence-tyylinen tietopankki asiakaspalvelijoille

Uusi moduuli "Ohjeet" jossa ylläpitäjä voi kirjoittaa ohjeita
asiakaspalvelijoille miten asioita tehdään.

Ominaisuudet:
- Korttipohjainen listanäkymä (grid) hakutoiminnolla ja kategoriasuodatuksella
- Markdown-editori toolbarilla (B, I, H2, H3, listat, linkit, koodi, lainaukset)
- Esikatselu-toggle muokkausnäkymässä
- Artikkelien lukunäkymä renderoitulla Markdownilla
- Kategorioiden hallinta (lisää/poista)
- Tagit ja kiinnitys (pinned) -toiminto
- Oikeushallinta: kaikki lukevat, admin luo/muokkaa/poistaa
- Moduuli näkyy/piiloutuu yrityskohtaisista asetuksista
- Muutokset kirjautuvat muutoslokiin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 12:19:00 +02:00
parent f4f11505d2
commit 7c4060bfa8
5 changed files with 636 additions and 2 deletions

94
api.php
View File

@@ -1912,6 +1912,100 @@ switch ($action) {
echo json_encode(['success' => true]);
break;
// ---------- OHJEET (GUIDES) ----------
case 'guides':
requireAuth();
$companyId = requireCompany();
echo json_encode(dbLoadGuides($companyId));
break;
case 'guide':
requireAuth();
requireCompany();
$id = $_GET['id'] ?? '';
$guide = dbLoadGuide($id);
if (!$guide) { http_response_code(404); echo json_encode(['error' => 'Ohjetta ei löydy']); exit; }
echo json_encode($guide);
break;
case 'guide_save':
requireAuth();
requireAdmin();
$companyId = requireCompany();
if ($method !== 'POST') break;
$input = json_decode(file_get_contents('php://input'), true);
$isNew = empty($input['id']);
$guide = [
'id' => $input['id'] ?? generateId(),
'category_id' => $input['category_id'] ?? null,
'title' => trim($input['title'] ?? ''),
'content' => $input['content'] ?? '',
'tags' => trim($input['tags'] ?? ''),
'author' => $isNew ? currentUser() : ($input['author'] ?? currentUser()),
'pinned' => !empty($input['pinned']),
'luotu' => $isNew ? date('Y-m-d H:i:s') : ($input['luotu'] ?? date('Y-m-d H:i:s')),
'muokattu' => $isNew ? null : date('Y-m-d H:i:s'),
'muokkaaja' => $isNew ? '' : currentUser(),
];
if (empty($guide['title'])) {
http_response_code(400);
echo json_encode(['error' => 'Otsikko vaaditaan']);
exit;
}
dbSaveGuide($companyId, $guide);
dbAddLog($companyId, currentUser(), $isNew ? 'guide_create' : 'guide_update', $guide['id'], $guide['title'], ($isNew ? 'Loi' : 'Muokkasi') . ' ohjeen');
echo json_encode($guide);
break;
case 'guide_delete':
requireAuth();
requireAdmin();
$companyId = requireCompany();
if ($method !== 'POST') break;
$input = json_decode(file_get_contents('php://input'), true);
$id = $input['id'] ?? '';
$guide = dbLoadGuide($id);
dbDeleteGuide($id);
dbAddLog($companyId, currentUser(), 'guide_delete', $id, $guide ? $guide['title'] : '', 'Poisti ohjeen');
echo json_encode(['success' => true]);
break;
case 'guide_categories':
requireAuth();
$companyId = requireCompany();
echo json_encode(dbLoadGuideCategories($companyId));
break;
case 'guide_category_save':
requireAuth();
requireAdmin();
$companyId = requireCompany();
if ($method !== 'POST') break;
$input = json_decode(file_get_contents('php://input'), true);
$cat = [
'id' => $input['id'] ?? generateId(),
'nimi' => trim($input['nimi'] ?? ''),
'sort_order' => (int)($input['sort_order'] ?? 0),
];
if (empty($cat['nimi'])) {
http_response_code(400);
echo json_encode(['error' => 'Kategorian nimi vaaditaan']);
exit;
}
dbSaveGuideCategory($companyId, $cat);
echo json_encode($cat);
break;
case 'guide_category_delete':
requireAuth();
requireAdmin();
$companyId = requireCompany();
if ($method !== 'POST') break;
$input = json_decode(file_get_contents('php://input'), true);
dbDeleteGuideCategory($input['id'] ?? '');
echo json_encode(['success' => true]);
break;
// ---------- ARCHIVE ----------
case 'archived_customers':
requireAuth();