Merge branch 'WorkorderMph/improve' into 'master'
Add spliceCompleted functionality and update WorkorderMph components See merge request fronk/thetool!1904
This commit is contained in:
@@ -118,6 +118,14 @@ class WorkorderMphAdminController extends WorkorderMphBaseController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getWorkorderByIdAction()
|
||||||
|
{
|
||||||
|
if (empty($this->request->id)) self::sendError("ID fehlt.");
|
||||||
|
$workorder = WorkorderMphModel::get($this->request->id);
|
||||||
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
||||||
|
self::returnJson((array)$workorder);
|
||||||
|
}
|
||||||
|
|
||||||
protected function getCompaniesAction()
|
protected function getCompaniesAction()
|
||||||
{
|
{
|
||||||
$companies = WorkorderCompanyModel::getAll();
|
$companies = WorkorderCompanyModel::getAll();
|
||||||
|
|||||||
@@ -18,29 +18,12 @@ class WorkorderMphBaseController extends TTCrud
|
|||||||
protected array $additionalJS = ["js/pages/WorkorderMphBase/WorkorderMphBase.js"];
|
protected array $additionalJS = ["js/pages/WorkorderMphBase/WorkorderMphBase.js"];
|
||||||
protected array $additionalHead = ["<link rel='stylesheet' href='/js/pages/WorkorderMphBase/WorkorderMphBase.css'>"];
|
protected array $additionalHead = ["<link rel='stylesheet' href='/js/pages/WorkorderMphBase/WorkorderMphBase.css'>"];
|
||||||
|
|
||||||
// Wohneinheit status options
|
|
||||||
protected array $wohneinheitStatuses = [
|
|
||||||
['value' => 1, 'text' => '10 - new'],
|
|
||||||
['value' => 12, 'text' => '241 - BEP installed (MD)'],
|
|
||||||
['value' => 13, 'text' => '242 - Inhouse cabling finished'],
|
|
||||||
['value' => 18, 'text' => '243 - Cable in stairwell'],
|
|
||||||
['value' => 14, 'text' => '244 - BEP installed (SD)'],
|
|
||||||
['value' => 15, 'text' => '245 - Installation Approved'],
|
|
||||||
['value' => 16, 'text' => '300 - ONT installed'],
|
|
||||||
];
|
|
||||||
|
|
||||||
protected function getStatusText(string $statusKey): string
|
protected function getStatusText(string $statusKey): string
|
||||||
{
|
{
|
||||||
$statusMap = array_column($this->statusColumn['table']['filterOptions'] ?? [], 'text', 'value');
|
$statusMap = array_column($this->statusColumn['table']['filterOptions'] ?? [], 'text', 'value');
|
||||||
return $statusMap[$statusKey] ?? ucfirst(str_replace('_', ' ', $statusKey));
|
return $statusMap[$statusKey] ?? ucfirst(str_replace('_', ' ', $statusKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getWohneinheitStatusText(int $statusValue): string
|
|
||||||
{
|
|
||||||
$statusMap = array_column($this->wohneinheitStatuses, 'text', 'value');
|
|
||||||
return $statusMap[$statusValue] ?? "Status $statusValue";
|
|
||||||
}
|
|
||||||
|
|
||||||
//region SHARED ACTIONS
|
//region SHARED ACTIONS
|
||||||
/**
|
/**
|
||||||
* Fetches documentation and journal entries for a given workorder.
|
* Fetches documentation and journal entries for a given workorder.
|
||||||
@@ -143,38 +126,75 @@ class WorkorderMphBaseController extends TTCrud
|
|||||||
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
||||||
$hausnummerId = $db->escape($workorder->hausnummerId);
|
$hausnummerId = $db->escape($workorder->hausnummerId);
|
||||||
|
|
||||||
$sql = "SELECT w.id, w.bezeichner, w.contact, w.oaid, w.note
|
// Fetch statuses from addressdb
|
||||||
|
$statusSql = "SELECT id, code, name FROM Status WHERE type = 'wohneinheit' ORDER BY code ASC";
|
||||||
|
$statusResult = $db->query($statusSql);
|
||||||
|
$statuses = $statusResult ? $statusResult->fetch_all(MYSQLI_ASSOC) : [];
|
||||||
|
|
||||||
|
$statusOptions = array_map(function($s) {
|
||||||
|
return ['value' => intval($s['id']), 'text' => $s['code'] . ' - ' . $s['name'], 'code' => intval($s['code'])];
|
||||||
|
}, $statuses);
|
||||||
|
|
||||||
|
// Fetch Wohneinheiten directly
|
||||||
|
$sql = "SELECT w.id, w.zusatz, w.tuer, w.contact, w.oaid, w.note, w.status_id, w.splice_hak_completed
|
||||||
FROM Wohneinheit w
|
FROM Wohneinheit w
|
||||||
WHERE w.hausnummer_id = $hausnummerId
|
WHERE w.hausnummer_id = $hausnummerId
|
||||||
ORDER BY w.bezeichner";
|
ORDER BY w.zusatz";
|
||||||
$result = $db->query($sql);
|
$result = $db->query($sql);
|
||||||
$wohneinheiten = $result ? $result->fetch_all(MYSQLI_ASSOC) : [];
|
$wohneinheiten = $result ? $result->fetch_all(MYSQLI_ASSOC) : [];
|
||||||
|
|
||||||
// Get existing WorkorderMphWohneinheit records
|
// Get Preorders for this Hausnummer to fallback contact info
|
||||||
$existingRecords = WorkorderMphWohneinheitModel::getAll(['workorderMphId' => $workorderMphId]);
|
$preorders = [];
|
||||||
$recordsMap = [];
|
if (class_exists('PreorderModel')) {
|
||||||
foreach ($existingRecords as $record) {
|
$preorderList = PreorderModel::search(['adb_hausnummer_id' => $workorder->hausnummerId, 'deleted' => 0]);
|
||||||
$recordsMap[$record->wohneinheitId] = $record;
|
foreach ($preorderList as $preorder) {
|
||||||
|
if ($preorder->adb_wohneinheit_id) {
|
||||||
|
$preorders[$preorder->adb_wohneinheit_id] = $preorder;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge data
|
// Merge data
|
||||||
$response = [];
|
$response = [];
|
||||||
foreach ($wohneinheiten as $we) {
|
foreach ($wohneinheiten as $we) {
|
||||||
$record = $recordsMap[$we['id']] ?? null;
|
// Contact info logic
|
||||||
// Prefer WorkorderMphWohneinheit note, fallback to addressdb note
|
$contact = $we['contact'];
|
||||||
$note = $record ? $record->note : $we['note'];
|
$preorderContact = null;
|
||||||
|
$preorderUcode = null;
|
||||||
|
|
||||||
|
if (isset($preorders[$we['id']])) {
|
||||||
|
$p = $preorders[$we['id']];
|
||||||
|
$preorderUcode = $p->ucode;
|
||||||
|
$pContact = trim($p->firstname . ' ' . $p->lastname);
|
||||||
|
if ($p->phone) $pContact .= ' (' . $p->phone . ')';
|
||||||
|
|
||||||
|
$preorderContact = $pContact;
|
||||||
|
|
||||||
|
// If address contact is empty, use preorder contact
|
||||||
|
if (empty($contact)) {
|
||||||
|
$contact = $pContact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$response[] = [
|
$response[] = [
|
||||||
'wohneinheitId' => intval($we['id']),
|
'wohneinheitId' => intval($we['id']),
|
||||||
'bezeichner' => $we['bezeichner'],
|
'zusatz' => $we['zusatz'],
|
||||||
'contact' => $we['contact'],
|
'tuer' => $we['tuer'],
|
||||||
|
'contact' => $contact,
|
||||||
|
'preorderContact' => $preorderContact,
|
||||||
|
'preorderUcode' => $preorderUcode,
|
||||||
'oaid' => $we['oaid'],
|
'oaid' => $we['oaid'],
|
||||||
'status' => $record ? $record->status : 1,
|
'status' => intval($we['status_id']),
|
||||||
'note' => $note,
|
'spliceCompleted' => intval($we['splice_hak_completed'] ?? 0),
|
||||||
'recordId' => $record ? $record->id : null,
|
'note' => $we['note'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
self::returnJson(['wohneinheiten' => $response, 'statusOptions' => $this->wohneinheitStatuses]);
|
self::returnJson([
|
||||||
|
'wohneinheiten' => $response,
|
||||||
|
'statusOptions' => $statusOptions,
|
||||||
|
'hausnummerId' => $workorder->hausnummerId
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,63 +209,86 @@ class WorkorderMphBaseController extends TTCrud
|
|||||||
|
|
||||||
$workorderMphId = intval($post['workorderMphId']);
|
$workorderMphId = intval($post['workorderMphId']);
|
||||||
$wohneinheitId = intval($post['wohneinheitId']);
|
$wohneinheitId = intval($post['wohneinheitId']);
|
||||||
$status = intval($post['status'] ?? 1);
|
$newStatusId = intval($post['status'] ?? 1);
|
||||||
$note = $post['note'] ?? null;
|
$spliceCompleted = isset($post['spliceCompleted']) ? intval($post['spliceCompleted']) : 0;
|
||||||
|
$tuer = $post['tuer'] ?? null;
|
||||||
|
$zusatz = $post['zusatz'] ?? null;
|
||||||
|
|
||||||
// Check if record exists
|
|
||||||
$existing = WorkorderMphWohneinheitModel::getFirst([
|
|
||||||
'workorderMphId' => $workorderMphId,
|
|
||||||
'wohneinheitId' => $wohneinheitId
|
|
||||||
]);
|
|
||||||
|
|
||||||
$oldStatus = $existing ? $existing->status : 1;
|
|
||||||
$oldNote = $existing ? $existing->note : null;
|
|
||||||
|
|
||||||
if ($existing) {
|
|
||||||
$existing->status = $status;
|
|
||||||
$existing->note = $note;
|
|
||||||
$existing->edit = time();
|
|
||||||
$existing->editBy = $this->user->id;
|
|
||||||
WorkorderMphWohneinheitModel::update((array)$existing);
|
|
||||||
} else {
|
|
||||||
WorkorderMphWohneinheitModel::create([
|
|
||||||
'workorderMphId' => $workorderMphId,
|
|
||||||
'wohneinheitId' => $wohneinheitId,
|
|
||||||
'status' => $status,
|
|
||||||
'note' => $note,
|
|
||||||
'create' => time(),
|
|
||||||
'createBy' => $this->user->id
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also save note to addressdb.Wohneinheit
|
|
||||||
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
||||||
$escapedNote = $note !== null ? "'" . $db->escape($note) . "'" : "NULL";
|
|
||||||
$escapedWohneinheitId = $db->escape($wohneinheitId);
|
$escapedWohneinheitId = $db->escape($wohneinheitId);
|
||||||
$updateSql = "UPDATE Wohneinheit SET note = $escapedNote WHERE id = $escapedWohneinheitId";
|
|
||||||
|
// Fetch current state
|
||||||
|
$currentSql = "SELECT status_id, tuer, zusatz, splice_hak_completed FROM Wohneinheit WHERE id = $escapedWohneinheitId";
|
||||||
|
$result = $db->query($currentSql);
|
||||||
|
$current = $result ? $result->fetch_assoc() : null;
|
||||||
|
|
||||||
|
if (!$current) self::sendError("Wohneinheit nicht gefunden.");
|
||||||
|
|
||||||
|
$oldStatusId = intval($current['status_id']);
|
||||||
|
$oldTuer = $current['tuer'];
|
||||||
|
$oldZusatz = $current['zusatz'];
|
||||||
|
$oldSplice = intval($current['splice_hak_completed'] ?? 0);
|
||||||
|
|
||||||
|
// Update Wohneinheit
|
||||||
|
$escapedTuer = $tuer !== null ? "'" . $db->escape($tuer) . "'" : "NULL";
|
||||||
|
$escapedZusatz = $zusatz !== null ? "'" . $db->escape($zusatz) . "'" : "NULL";
|
||||||
|
$escapedStatusId = $db->escape($newStatusId);
|
||||||
|
$escapedSplice = $db->escape($spliceCompleted);
|
||||||
|
|
||||||
|
$updateSql = "UPDATE Wohneinheit SET
|
||||||
|
status_id = $escapedStatusId,
|
||||||
|
tuer = $escapedTuer,
|
||||||
|
zusatz = $escapedZusatz,
|
||||||
|
splice_hak_completed = $escapedSplice
|
||||||
|
WHERE id = $escapedWohneinheitId";
|
||||||
|
|
||||||
$db->query($updateSql);
|
$db->query($updateSql);
|
||||||
|
|
||||||
// Add journal entry if status or note changed
|
// Journaling
|
||||||
if ($oldStatus !== $status || $oldNote !== $note) {
|
$changes = [];
|
||||||
$changes = [];
|
if ($oldStatusId !== $newStatusId) {
|
||||||
if ($oldStatus !== $status) {
|
// Fetch status names for better logging
|
||||||
$changes[] = "Status: " . $this->getWohneinheitStatusText($oldStatus) . " → " . $this->getWohneinheitStatusText($status);
|
$statusNamesSql = "SELECT id, code, name FROM Status WHERE id IN ($oldStatusId, $newStatusId)";
|
||||||
}
|
$statusRes = $db->query($statusNamesSql);
|
||||||
if ($oldNote !== $note) {
|
$statusMap = [];
|
||||||
$changes[] = "Notiz aktualisiert";
|
if ($statusRes) {
|
||||||
}
|
while($row = $statusRes->fetch_assoc()) {
|
||||||
|
$statusMap[$row['id']] = $row['code'] . ' - ' . $row['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$oldText = $statusMap[$oldStatusId] ?? "ID $oldStatusId";
|
||||||
|
$newText = $statusMap[$newStatusId] ?? "ID $newStatusId";
|
||||||
|
$changes[] = "Status: $oldText → $newText";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oldSplice !== $spliceCompleted) {
|
||||||
|
$changes[] = "Spleiß: " . ($spliceCompleted ? 'Erledigt' : 'Nicht erledigt');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oldTuer !== $tuer) {
|
||||||
|
$changes[] = "Tür aktualisiert: '$oldTuer' -> '$tuer'";
|
||||||
|
}
|
||||||
|
if ($oldZusatz !== $zusatz) {
|
||||||
|
$changes[] = "Zusatz aktualisiert: '$oldZusatz' -> '$zusatz'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($changes)) {
|
||||||
WorkorderMphJournalModel::create([
|
WorkorderMphJournalModel::create([
|
||||||
'workorderMphId' => $workorderMphId,
|
'workorderMphId' => $workorderMphId,
|
||||||
'text' => "Wohneinheit $wohneinheitId: " . implode(', ', $changes),
|
'text' => "Wohneinheit $wohneinheitId: " . implode(', ', $changes),
|
||||||
'create' => time(),
|
'create' => time(),
|
||||||
'createBy' => $this->user->id,
|
'createBy' => $this->user->id,
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
// If status is 241 (BEP MD) or 300 (ONT installed), set statusflag 200 on Wohneinheit
|
// Status flag logic for BEP MD (241) and ONT (300). Need to check codes for these IDs.
|
||||||
if (in_array($status, [12, 16])) { // 12=241 BEP MD, 16=300 ONT
|
// Since we only have IDs, we need to check the code of the newStatusId.
|
||||||
$this->setWohneinheitStatusflag($wohneinheitId, 200);
|
$newStatusCodeSql = "SELECT code FROM Status WHERE id = $escapedStatusId";
|
||||||
}
|
$resCode = $db->query($newStatusCodeSql);
|
||||||
|
$newStatusCode = $resCode ? intval($resCode->fetch_assoc()['code']) : 0;
|
||||||
|
|
||||||
|
if (in_array($newStatusCode, [241, 300])) { // 241=BEP MD, 300=ONT
|
||||||
|
$this->setWohneinheitStatusflag($wohneinheitId, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
self::returnJson(['success' => true, 'message' => 'Wohneinheit aktualisiert.']);
|
self::returnJson(['success' => true, 'message' => 'Wohneinheit aktualisiert.']);
|
||||||
@@ -286,6 +329,8 @@ class WorkorderMphBaseController extends TTCrud
|
|||||||
$changes = [];
|
$changes = [];
|
||||||
$checkboxFields = ['easement', 'btb', 'fttxLocationSupplied', 'conduitToHuepLaid', 'huepMounted', 'dropCableAvailable', 'spliceCompleted'];
|
$checkboxFields = ['easement', 'btb', 'fttxLocationSupplied', 'conduitToHuepLaid', 'huepMounted', 'dropCableAvailable', 'spliceCompleted'];
|
||||||
|
|
||||||
|
$updateHausnummerStatus = false;
|
||||||
|
|
||||||
foreach ($checkboxFields as $field) {
|
foreach ($checkboxFields as $field) {
|
||||||
if (array_key_exists($field, $post)) {
|
if (array_key_exists($field, $post)) {
|
||||||
$oldValue = $workorder->$field;
|
$oldValue = $workorder->$field;
|
||||||
@@ -293,6 +338,11 @@ class WorkorderMphBaseController extends TTCrud
|
|||||||
if ($oldValue !== $newValue) {
|
if ($oldValue !== $newValue) {
|
||||||
$workorder->$field = $newValue;
|
$workorder->$field = $newValue;
|
||||||
$changes[] = "$field: " . ($newValue ? 'ja' : 'nein');
|
$changes[] = "$field: " . ($newValue ? 'ja' : 'nein');
|
||||||
|
|
||||||
|
// Check for FTTx Location mit Leerrohr versorgt
|
||||||
|
if ($field === 'fttxLocationSupplied' && $newValue === 1) {
|
||||||
|
$updateHausnummerStatus = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,6 +350,19 @@ class WorkorderMphBaseController extends TTCrud
|
|||||||
if (!empty($changes)) {
|
if (!empty($changes)) {
|
||||||
WorkorderMphModel::update((array)$workorder);
|
WorkorderMphModel::update((array)$workorder);
|
||||||
|
|
||||||
|
if ($updateHausnummerStatus) {
|
||||||
|
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
||||||
|
// Find status ID for code 200
|
||||||
|
$statusSql = "SELECT id FROM Status WHERE code = 200 AND type = 'hausnummer' LIMIT 1";
|
||||||
|
$statusResult = $db->query($statusSql);
|
||||||
|
if ($statusResult && $row = $statusResult->fetch_assoc()) {
|
||||||
|
$statusId = $row['id'];
|
||||||
|
$hnId = $db->escape($workorder->hausnummerId);
|
||||||
|
$updateHnSql = "UPDATE Hausnummer SET status_id = $statusId WHERE id = $hnId";
|
||||||
|
$db->query($updateHnSql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WorkorderMphJournalModel::create([
|
WorkorderMphJournalModel::create([
|
||||||
'workorderMphId' => $workorder->id,
|
'workorderMphId' => $workorder->id,
|
||||||
'text' => "Dokumentation aktualisiert:\n" . implode("\n", $changes),
|
'text' => "Dokumentation aktualisiert:\n" . implode("\n", $changes),
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class WorkorderMphWohneinheitModel extends TTCrudBaseModel
|
|
||||||
{
|
|
||||||
public int $id;
|
|
||||||
public int $workorderMphId;
|
|
||||||
public int $wohneinheitId;
|
|
||||||
public int $status;
|
|
||||||
public ?string $note;
|
|
||||||
public int $create;
|
|
||||||
public int $createBy;
|
|
||||||
public ?int $edit;
|
|
||||||
public ?int $editBy;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class AddSpliceCompletedToWorkorderMphWohneinheit extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
if ($this->getEnvironment() == "thetool") {
|
||||||
|
$table = $this->table('WorkorderMphWohneinheit');
|
||||||
|
if (!$table->hasColumn('spliceCompleted')) {
|
||||||
|
$table->addColumn('spliceCompleted', 'boolean', [
|
||||||
|
'null' => true,
|
||||||
|
'default' => 0,
|
||||||
|
'comment' => 'Spleiß im HÜP/HAK erledigt',
|
||||||
|
'after' => 'status'
|
||||||
|
]);
|
||||||
|
$table->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
if ($this->getEnvironment() == "thetool") {
|
||||||
|
$table = $this->table('WorkorderMphWohneinheit');
|
||||||
|
if ($table->hasColumn('spliceCompleted')) {
|
||||||
|
$table->removeColumn('spliceCompleted');
|
||||||
|
$table->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//SQL: ALTER TABLE `WorkorderMphWohneinheit` ADD COLUMN `spliceCompleted` TINYINT(1) NULL DEFAULT 0 COMMENT 'Spleiß im HÜP/HAK erledigt' AFTER `status`;
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class RefactorWorkorderMphWohneinheit extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// AddressDB modifications
|
||||||
|
if ($this->getEnvironment() == "addressdb") {
|
||||||
|
$table = $this->table('Wohneinheit');
|
||||||
|
if (!$table->hasColumn('splice_hak_completed')) {
|
||||||
|
$table->addColumn('splice_hak_completed', 'boolean', [
|
||||||
|
'null' => true,
|
||||||
|
'default' => 0,
|
||||||
|
'after' => 'external_data'
|
||||||
|
]);
|
||||||
|
$table->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TheTool modifications
|
||||||
|
if ($this->getEnvironment() == "thetool") {
|
||||||
|
$table = $this->table('WorkorderMphWohneinheit');
|
||||||
|
if ($table->exists()) {
|
||||||
|
$table->drop()->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
// AddressDB modifications
|
||||||
|
if ($this->getEnvironment() == "addressdb") {
|
||||||
|
$table = $this->table('Wohneinheit');
|
||||||
|
if ($table->hasColumn('splice_hak_completed')) {
|
||||||
|
$table->removeColumn('splice_hak_completed');
|
||||||
|
$table->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TheTool modifications
|
||||||
|
if ($this->getEnvironment() == "thetool") {
|
||||||
|
$table = $this->table('WorkorderMphWohneinheit');
|
||||||
|
if (!$table->exists()) {
|
||||||
|
$table->addColumn('workorderMphId', 'integer')
|
||||||
|
->addColumn('wohneinheitId', 'integer')
|
||||||
|
->addColumn('status', 'integer')
|
||||||
|
->addColumn('spliceCompleted', 'boolean', ['null' => true, 'default' => 0])
|
||||||
|
->addColumn('note', 'text', ['null' => true])
|
||||||
|
->addColumn('create', 'integer')
|
||||||
|
->addColumn('createBy', 'integer')
|
||||||
|
->addColumn('edit', 'integer', ['null' => true])
|
||||||
|
->addColumn('editBy', 'integer', ['null' => true])
|
||||||
|
->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -7,7 +7,7 @@ services:
|
|||||||
- "80:80"
|
- "80:80"
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/php/apache.conf:/etc/apache2/sites-available/000-default.conf
|
- ./docker/php/apache.conf:/etc/apache2/sites-available/000-default.conf
|
||||||
- ./docker/php/custom.ini:/etc/php/8.2/apache2/conf.d/99-custom.ini
|
- ./docker/php/custom.ini:/etc/php/8.4/apache2/conf.d/99-custom.ini
|
||||||
- ./docker/php/logs:/var/log/apache2
|
- ./docker/php/logs:/var/log/apache2
|
||||||
- ./:/var/www/html
|
- ./:/var/www/html
|
||||||
- vendor:/var/www/html/vendor
|
- vendor:/var/www/html/vendor
|
||||||
|
|||||||
@@ -57,16 +57,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.wohneinheit-manager .we-bezeichner {
|
.wohneinheit-manager .we-bezeichner {
|
||||||
width: 25%;
|
width: 20%;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wohneinheit-manager .we-status {
|
.wohneinheit-manager .we-status {
|
||||||
width: 20%;
|
width: 18%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wohneinheit-manager .we-splice {
|
||||||
|
width: 12%;
|
||||||
|
padding: 4px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wohneinheit-manager .we-note {
|
.wohneinheit-manager .we-note {
|
||||||
width: 40%;
|
width: 35%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wohneinheit-manager .we-actions {
|
.wohneinheit-manager .we-actions {
|
||||||
@@ -74,6 +79,26 @@
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wohneinheit-manager .we-splice .custom-checkbox-item {
|
||||||
|
padding: 4px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
height: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wohneinheit-manager .we-splice .custom-checkbox-item .checkmark {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wohneinheit-manager .we-splice .custom-checkbox-item .checkbox-label {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.contact-info {
|
.contact-info {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
|
|||||||
@@ -27,8 +27,11 @@ Vue.component('wohneinheit-status-manager', {
|
|||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div class="card wohneinheit-manager">
|
<div class="card wohneinheit-manager">
|
||||||
<div class="card-header bg-primary text-white">
|
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
|
||||||
<h5 class="mb-0"><i class="fas fa-building mr-2"></i>Wohneinheiten Status</h5>
|
<h5 class="mb-0"><i class="fas fa-building mr-2"></i>Wohneinheiten Status</h5>
|
||||||
|
<a v-if="hausnummerId" :href="'/AddressDB/view/?id=' + hausnummerId" target="_blank" class="text-white small">
|
||||||
|
<i class="fas fa-external-link-alt mr-1"></i>AddressDB #{{ hausnummerId }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="loading" class="text-center p-5"><i class="fas fa-spinner fa-spin fa-2x"></i></div>
|
<div v-if="loading" class="text-center p-5"><i class="fas fa-spinner fa-spin fa-2x"></i></div>
|
||||||
<div v-else class="card-body p-0">
|
<div v-else class="card-body p-0">
|
||||||
@@ -36,35 +39,56 @@ Vue.component('wohneinheit-status-manager', {
|
|||||||
Keine Wohneinheiten gefunden.
|
Keine Wohneinheiten gefunden.
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="we-table">
|
<div v-else class="we-table">
|
||||||
<div v-for="we in wohneinheiten" :key="we.wohneinheitId" class="we-row">
|
<div v-for="we in wohneinheiten" :key="we.wohneinheitId" class="we-row" :class="{ 'locked-row': isLocked(we) }">
|
||||||
<div class="we-cell we-bezeichner">
|
<div class="we-cell we-zusatz">
|
||||||
<strong>{{ we.bezeichner }}</strong>
|
<div class="form-group mb-1">
|
||||||
|
<small class="text-muted">Zusatz</small>
|
||||||
|
<input type="text" class="form-control form-control-sm" v-model="we.zusatz"
|
||||||
|
@input="debouncedSave(we)" :disabled="isLocked(we)">
|
||||||
|
</div>
|
||||||
<div class="text-muted small">
|
<div class="text-muted small">
|
||||||
<i class="fas fa-id-card mr-1"></i>OAID: {{ we.oaid }}
|
<i class="fas fa-id-card mr-1"></i>OAID: {{ we.oaid }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="we.contact" class="contact-info text-muted">
|
<div v-if="we.contact" class="contact-info text-muted">
|
||||||
<i class="fas fa-user mr-1"></i>{{ we.contact }}
|
<i class="fas fa-user mr-1"></i>{{ we.contact }}
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="we.preorderContact" class="contact-info text-info" title="Daten aus Vorbestellung">
|
||||||
|
<i class="fas fa-user-check mr-1"></i>{{ we.preorderContact }}
|
||||||
|
</div>
|
||||||
<div v-else class="text-muted small fst-italic">
|
<div v-else class="text-muted small fst-italic">
|
||||||
<i class="fas fa-user-slash mr-1"></i>Keine Kontaktinfo
|
<i class="fas fa-user-slash mr-1"></i>Keine Kontaktinfo
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="we.preorderUcode" class="mt-1">
|
||||||
|
<a :href="'/Preorder/Index?filter[ucode]=' + we.preorderUcode" target="_blank" class="badge badge-info">
|
||||||
|
<i class="fas fa-shopping-cart mr-1"></i>Vorbestellung
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="we-cell we-tuer">
|
||||||
|
<div class="form-group mb-0">
|
||||||
|
<small class="text-muted">Tür</small>
|
||||||
|
<input type="text" class="form-control form-control-sm" v-model="we.tuer"
|
||||||
|
@input="debouncedSave(we)" :disabled="isLocked(we)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="we-cell we-status">
|
<div class="we-cell we-status">
|
||||||
<tt-select v-model="we.status" :options="statusOptions" sm no-form-group
|
<small class="text-muted d-block mb-1">Status</small>
|
||||||
:disabled="isAdmin" @input="markAsChanged(we)"/>
|
<div v-if="isLocked(we)" class="locked-status">
|
||||||
|
<i class="fas fa-lock mr-1"></i> {{ getStatusText(we.status) }}
|
||||||
|
</div>
|
||||||
|
<tt-select v-else v-model="we.status" :options="filteredStatusOptions" sm no-form-group
|
||||||
|
@input="saveWohneinheit(we)"/>
|
||||||
|
<div v-if="we.saving" class="text-muted small mt-1"><i class="fas fa-sync fa-spin mr-1"></i>Speichert...</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="we-cell we-note">
|
<div class="we-cell we-splice text-center">
|
||||||
<tt-textarea v-model="we.note" sm rows="1" no-form-group
|
<label class="custom-checkbox-item mb-0" title="Spleiß im HÜP/HAK erledigt">
|
||||||
:disabled="isAdmin"
|
<input type="checkbox" v-model="we.spliceCompleted" @change="saveWohneinheit(we)" :disabled="isLocked(we)">
|
||||||
@input="markAsChanged(we)"
|
<span class="checkmark small-checkmark"></span>
|
||||||
:placeholder="isAdmin ? 'Keine Notiz' : 'Pflichtfeld'"/>
|
<span class="d-block small mt-1">Spleiß</span>
|
||||||
</div>
|
</label>
|
||||||
<div class="we-cell we-actions">
|
|
||||||
<span v-if="we.changed" class="text-warning small">
|
|
||||||
<i class="fas fa-exclamation-triangle"></i>
|
|
||||||
</span>
|
|
||||||
<tt-button v-if="!isAdmin" @click="saveWohneinheit(we)" text="Speichern" sm
|
|
||||||
:loading="we.saving" :disabled="!we.changed"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,8 +98,16 @@ Vue.component('wohneinheit-status-manager', {
|
|||||||
data: () => ({
|
data: () => ({
|
||||||
loading: true,
|
loading: true,
|
||||||
wohneinheiten: [],
|
wohneinheiten: [],
|
||||||
statusOptions: []
|
statusOptions: [],
|
||||||
|
hausnummerId: null,
|
||||||
|
debounceTimers: {}
|
||||||
}),
|
}),
|
||||||
|
computed: {
|
||||||
|
filteredStatusOptions() {
|
||||||
|
// Filter out status with code 300
|
||||||
|
return this.statusOptions.filter(opt => opt.code !== 300);
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchWohneinheiten() {
|
async fetchWohneinheiten() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
@@ -86,10 +118,11 @@ Vue.component('wohneinheit-status-manager', {
|
|||||||
});
|
});
|
||||||
this.wohneinheiten = data.wohneinheiten.map(we => ({
|
this.wohneinheiten = data.wohneinheiten.map(we => ({
|
||||||
...we,
|
...we,
|
||||||
changed: false,
|
spliceCompleted: !!we.spliceCompleted,
|
||||||
saving: false
|
saving: false
|
||||||
}));
|
}));
|
||||||
this.statusOptions = data.statusOptions || [];
|
this.statusOptions = data.statusOptions || [];
|
||||||
|
this.hausnummerId = data.hausnummerId;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
window.notify('error', 'Wohneinheiten konnten nicht geladen werden.');
|
window.notify('error', 'Wohneinheiten konnten nicht geladen werden.');
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -97,25 +130,33 @@ Vue.component('wohneinheit-status-manager', {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
markAsChanged(we) {
|
isLocked(we) {
|
||||||
we.changed = true;
|
const status = this.statusOptions.find(s => s.value === we.status);
|
||||||
|
return status && status.code === 300;
|
||||||
|
},
|
||||||
|
debouncedSave(we) {
|
||||||
|
we.saving = true;
|
||||||
|
if (this.debounceTimers[we.wohneinheitId]) {
|
||||||
|
clearTimeout(this.debounceTimers[we.wohneinheitId]);
|
||||||
|
}
|
||||||
|
this.debounceTimers[we.wohneinheitId] = setTimeout(() => {
|
||||||
|
this.saveWohneinheit(we);
|
||||||
|
}, 1000);
|
||||||
},
|
},
|
||||||
async saveWohneinheit(we) {
|
async saveWohneinheit(we) {
|
||||||
if (!we.note || !we.note.trim()) {
|
|
||||||
return window.notify('error', 'Bitte eine Notiz eingeben.');
|
|
||||||
}
|
|
||||||
|
|
||||||
we.saving = true;
|
we.saving = true;
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderMphCompany/updateWohneinheit`, {
|
const basePath = this.isAdmin ? '/WorkorderMphAdmin' : '/WorkorderMphCompany';
|
||||||
|
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}${basePath}/updateWohneinheit`, {
|
||||||
workorderMphId: this.workorderMphId,
|
workorderMphId: this.workorderMphId,
|
||||||
wohneinheitId: we.wohneinheitId,
|
wohneinheitId: we.wohneinheitId,
|
||||||
status: we.status,
|
status: we.status,
|
||||||
note: we.note
|
spliceCompleted: we.spliceCompleted ? 1 : 0,
|
||||||
|
tuer: we.tuer,
|
||||||
|
zusatz: we.zusatz
|
||||||
});
|
});
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
window.notify('success', data.message);
|
// Silent success or small indicator
|
||||||
we.changed = false;
|
|
||||||
this.$emit('wohneinheit-updated');
|
this.$emit('wohneinheit-updated');
|
||||||
} else {
|
} else {
|
||||||
window.notify('error', data.message || 'Speichern fehlgeschlagen.');
|
window.notify('error', data.message || 'Speichern fehlgeschlagen.');
|
||||||
@@ -149,51 +190,44 @@ Vue.component('checkbox-documentation', {
|
|||||||
<div v-if="loading" class="text-center p-3"><i class="fas fa-spinner fa-spin"></i></div>
|
<div v-if="loading" class="text-center p-3"><i class="fas fa-spinner fa-spin"></i></div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="custom-checkboxes-grid">
|
<div class="custom-checkboxes-grid">
|
||||||
<label class="custom-checkbox-item" :class="{ disabled: isAdmin }">
|
<label class="custom-checkbox-item">
|
||||||
<input type="checkbox" v-model="checkboxes.easement" :disabled="isAdmin">
|
<input type="checkbox" v-model="checkboxes.easement" @change="saveCheckboxes">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
<span class="checkbox-label">Leitungsrecht</span>
|
<span class="checkbox-label">Leitungsrecht</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="custom-checkbox-item" :class="{ disabled: isAdmin }">
|
<label class="custom-checkbox-item">
|
||||||
<input type="checkbox" v-model="checkboxes.btb" :disabled="isAdmin">
|
<input type="checkbox" v-model="checkboxes.btb" @change="saveCheckboxes">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
<span class="checkbox-label">BTB</span>
|
<span class="checkbox-label">Betriebstechnische Begehung</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="custom-checkbox-item" :class="{ disabled: isAdmin }">
|
<label class="custom-checkbox-item">
|
||||||
<input type="checkbox" v-model="checkboxes.fttxLocationSupplied" :disabled="isAdmin">
|
<input type="checkbox" v-model="checkboxes.fttxLocationSupplied" @change="saveCheckboxes">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
<span class="checkbox-label">FTTx Location mit Leerrohr versorgt</span>
|
<span class="checkbox-label">FTTx Location mit Leerrohr versorgt</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="custom-checkbox-item" :class="{ disabled: isAdmin }">
|
<label class="custom-checkbox-item">
|
||||||
<input type="checkbox" v-model="checkboxes.conduitToHuepLaid" :disabled="isAdmin">
|
<input type="checkbox" v-model="checkboxes.conduitToHuepLaid" @change="saveCheckboxes">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
<span class="checkbox-label">Leerrohr bis HÜP/HAK verlegt</span>
|
<span class="checkbox-label">Leerrohr bis HÜP/HAK verlegt</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="custom-checkbox-item" :class="{ disabled: isAdmin }">
|
<label class="custom-checkbox-item">
|
||||||
<input type="checkbox" v-model="checkboxes.huepMounted" :disabled="isAdmin">
|
<input type="checkbox" v-model="checkboxes.huepMounted" @change="saveCheckboxes">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
<span class="checkbox-label">HÜP/HAK montiert</span>
|
<span class="checkbox-label">HÜP/HAK montiert</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="custom-checkbox-item" :class="{ disabled: isAdmin }">
|
<label class="custom-checkbox-item">
|
||||||
<input type="checkbox" v-model="checkboxes.dropCableAvailable" :disabled="isAdmin">
|
<input type="checkbox" v-model="checkboxes.dropCableAvailable" @change="saveCheckboxes">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
<span class="checkbox-label">Dropkabel vorhanden</span>
|
<span class="checkbox-label">Dropkabel vorhanden</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="custom-checkbox-item" :class="{ disabled: isAdmin }">
|
|
||||||
<input type="checkbox" v-model="checkboxes.spliceCompleted" :disabled="isAdmin">
|
|
||||||
<span class="checkmark"></span>
|
|
||||||
<span class="checkbox-label">Spleiß im HÜP/HAK erledigt</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 text-right" v-if="!isAdmin">
|
<div v-if="saving" class="mt-2 text-right text-muted small">
|
||||||
<tt-button @click="saveCheckboxes" text="Speichern"
|
<i class="fas fa-sync fa-spin mr-1"></i>Speichert...
|
||||||
:loading="saving" additional-class="btn-primary btn-sm"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,15 +242,15 @@ Vue.component('checkbox-documentation', {
|
|||||||
fttxLocationSupplied: false,
|
fttxLocationSupplied: false,
|
||||||
conduitToHuepLaid: false,
|
conduitToHuepLaid: false,
|
||||||
huepMounted: false,
|
huepMounted: false,
|
||||||
dropCableAvailable: false,
|
dropCableAvailable: false
|
||||||
spliceCompleted: false
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
async fetchCheckboxes() {
|
async fetchCheckboxes() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`${window.TT_CONFIG.BASE_PATH}/WorkorderMphCompany/getWorkorderById`, {
|
const basePath = this.isAdmin ? '/WorkorderMphAdmin' : '/WorkorderMphCompany';
|
||||||
|
const { data } = await axios.get(`${window.TT_CONFIG.BASE_PATH}${basePath}/getWorkorderById`, {
|
||||||
params: { id: this.workorderMphId }
|
params: { id: this.workorderMphId }
|
||||||
});
|
});
|
||||||
this.checkboxes = {
|
this.checkboxes = {
|
||||||
@@ -225,8 +259,7 @@ Vue.component('checkbox-documentation', {
|
|||||||
fttxLocationSupplied: !!data.fttxLocationSupplied,
|
fttxLocationSupplied: !!data.fttxLocationSupplied,
|
||||||
conduitToHuepLaid: !!data.conduitToHuepLaid,
|
conduitToHuepLaid: !!data.conduitToHuepLaid,
|
||||||
huepMounted: !!data.huepMounted,
|
huepMounted: !!data.huepMounted,
|
||||||
dropCableAvailable: !!data.dropCableAvailable,
|
dropCableAvailable: !!data.dropCableAvailable
|
||||||
spliceCompleted: !!data.spliceCompleted
|
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
window.notify('error', 'Checkboxen konnten nicht geladen werden.');
|
window.notify('error', 'Checkboxen konnten nicht geladen werden.');
|
||||||
@@ -238,12 +271,13 @@ Vue.component('checkbox-documentation', {
|
|||||||
async saveCheckboxes() {
|
async saveCheckboxes() {
|
||||||
this.saving = true;
|
this.saving = true;
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderMphCompany/updateCheckboxes`, {
|
const basePath = this.isAdmin ? '/WorkorderMphAdmin' : '/WorkorderMphCompany';
|
||||||
|
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}${basePath}/updateCheckboxes`, {
|
||||||
workorderMphId: this.workorderMphId,
|
workorderMphId: this.workorderMphId,
|
||||||
...this.checkboxes
|
...this.checkboxes
|
||||||
});
|
});
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
window.notify('success', data.message);
|
// Silent success
|
||||||
this.$emit('checkboxes-updated');
|
this.$emit('checkboxes-updated');
|
||||||
} else {
|
} else {
|
||||||
window.notify('error', data.message || 'Speichern fehlgeschlagen.');
|
window.notify('error', data.message || 'Speichern fehlgeschlagen.');
|
||||||
@@ -357,33 +391,21 @@ Vue.component('workorder-mph-details-manager', {
|
|||||||
<div class="card-body p-3">
|
<div class="card-body p-3">
|
||||||
<h5 class="card-title mb-3">Neues Dokument hochladen</h5>
|
<h5 class="card-title mb-3">Neues Dokument hochladen</h5>
|
||||||
|
|
||||||
<div class="form-group row mb-2">
|
<tt-select label="Dokumententyp*" :options="docTypeOptions" v-model="uploadData.documentType" sm row required/>
|
||||||
<label class="col-form-label col-sm-4 col-form-label-sm">Dokumententyp*</label>
|
<div v-if="uploadData.documentType" class="row mb-2">
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8 offset-sm-4">
|
||||||
<select v-model="uploadData.documentType" class="form-control form-control-sm" required>
|
<small class="form-text text-muted mt-0">
|
||||||
<option value="">-- Bitte wählen --</option>
|
<i class="fas fa-info-circle"></i> {{ getDocExample(uploadData.documentType) }}
|
||||||
<option v-for="doc in requiredDocs" :key="doc.key" :value="doc.key">
|
</small>
|
||||||
{{ doc.label }}
|
</div>
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<small v-if="uploadData.documentType" class="form-text text-muted">
|
|
||||||
<i class="fas fa-info-circle"></i> {{ getDocExample(uploadData.documentType) }}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group row mb-2">
|
<tt-input label="Beschreibung" v-model="uploadData.description" sm row placeholder="Optional: Zusätzliche Beschreibung"/>
|
||||||
<label class="col-form-label col-sm-4 col-form-label-sm">Beschreibung</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<input type="text" v-model="uploadData.description" class="form-control form-control-sm"
|
|
||||||
placeholder="Optional: Zusätzliche Beschreibung"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row mb-3">
|
<div class="form-group row mb-3">
|
||||||
<label class="col-form-label col-sm-4 col-form-label-sm">Dateien*</label>
|
<label class="col-form-label col-sm-4 col-form-label-sm">Dateien*</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="file" class="form-control-file form-control-sm"
|
<input type="file" class="form-control-file form-control-sm p-0"
|
||||||
@change="handleFileUpload" ref="fileInput" multiple accept="image/*,.pdf"/>
|
@change="handleFileUpload" ref="fileInput" multiple accept="image/*,.pdf"/>
|
||||||
<small class="form-text text-muted">Erlaubt: Bilder (JPG, PNG) und PDF</small>
|
<small class="form-text text-muted">Erlaubt: Bilder (JPG, PNG) und PDF</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -417,6 +439,12 @@ Vue.component('workorder-mph-details-manager', {
|
|||||||
},
|
},
|
||||||
canComplete() {
|
canComplete() {
|
||||||
return this.wohneinheitenWithNotes && this.docs.length > 0;
|
return this.wohneinheitenWithNotes && this.docs.length > 0;
|
||||||
|
},
|
||||||
|
docTypeOptions() {
|
||||||
|
return [
|
||||||
|
{ value: '', text: '-- Bitte wählen --' },
|
||||||
|
...this.requiredDocs.map(doc => ({ value: doc.key, text: doc.label }))
|
||||||
|
];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -490,7 +518,7 @@ Vue.component('workorder-mph-details-manager', {
|
|||||||
if (data.success) {
|
if (data.success) {
|
||||||
window.notify('success', data.message);
|
window.notify('success', data.message);
|
||||||
this.$refs.fileInput.value = '';
|
this.$refs.fileInput.value = '';
|
||||||
this.uploadData = { files: [], documentType: 'photo', description: '' };
|
this.uploadData = { files: [], documentType: '', description: '' };
|
||||||
await this.fetchData();
|
await this.fetchData();
|
||||||
} else {
|
} else {
|
||||||
window.notify('error', data.error || 'Upload fehlgeschlagen.');
|
window.notify('error', data.error || 'Upload fehlgeschlagen.');
|
||||||
|
|||||||
Reference in New Issue
Block a user