Webgui programming

This commit is contained in:
2025-05-09 10:22:08 +02:00
parent c293ca1caa
commit fb93c83388
11 changed files with 340 additions and 85 deletions
+2
View File
@@ -1,3 +1,5 @@
YMS - Yacht Management System
Prototype
Many features are incomplete, buggy or missing.
Use at your own risk!
+4 -1
View File
@@ -217,6 +217,7 @@ CREATE TABLE company (
compid smallint(6) NOT NULL AUTO_INCREMENT,
compname varchar(60) NOT NULL,
comptype tinyint(3) NOT NULL DEFAULT 1,
comptype2 tinyint(3) DEFAULT NULL,
shortname varchar(20) DEFAULT NULL,
street varchar(30),
zip varchar(10),
@@ -258,7 +259,7 @@ CREATE TABLE project (
costs_plan decimal(12,2) DEFAULT NULL,
costs_final decimal(12,2) DEFAULT NULL,
remarks varchar(150) DEFAULT NULL,
projstate enum('new','plan','ongoing','finished') NOT NULL DEFAULT 'new',
projstate enum('new','plan','ongoing','paused','finished') NOT NULL DEFAULT 'new',
PRIMARY KEY (projid)
);
@@ -273,6 +274,8 @@ CREATE TABLE task (
duedate date DEFAULT NULL,
started datetime DEFAULT NULL,
finished datetime DEFAULT NULL,
responsible smallint(6) NOT NULL,
/* TODO executed_by : company or user? or both? */
PRIMARY KEY (taskid)
);
+1 -1
View File
@@ -6,4 +6,4 @@ mv /var/www/html/config.inc-sample /var/www/html/config.inc
chmod 640 /var/www/html/config.inc
chgrp www-data /var/www/html/config.inc
rm /var/www/html/index.html
rm /var/www/html/locale/dc_DE.po
rm /var/www/html/locale/de_DE.po
+20 -3
View File
@@ -43,6 +43,7 @@ switch ($submit = form_get_action()) {
$p[':compname'] = gpc_get_string($_POST, 'compname');
$p[':shortname'] = gpc_get_string($_POST, 'shortname', 20);
$p[':comptype'] = gpc_get_int($_POST, 'comptype');
$p[':comptype2'] = gpc_get_int($_POST, 'comptype2');
$p[':street'] = gpc_get_string($_POST, 'street', 30);
$p[':zip'] = gpc_get_string($_POST, 'zip', 10);
$p[':city'] = gpc_get_string($_POST, 'city', 30);
@@ -228,8 +229,8 @@ echo '<h2>', _('Add Company'), "</h2>\n";
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT compname, comptype, shortname, street, zip, city, country,"
. " contact, phone, email, web, customerno, contractno, remarks "
$sql = "SELECT compname, comptype, comptype2, shortname, street, zip, city,"
. " country, contact, phone, email, web, customerno, contractno, remarks "
. "FROM company "
. "WHERE compid=?";
$sth = $pdo->prepare($sql);
@@ -242,6 +243,7 @@ echo '<table class="table">', "\n";
echo '<tr><th scope="row" style="width:20%">', _('Name'),"</th><td>", $company->compname, "</td></tr>\n";
echo '<tr><th scope="row">', _('Short name'),"</th><td>", $company->shortname, "</td></tr>\n";
echo '<tr><th scope="row">', _('Type'),"</th><td>", $opt_comptype[$company->comptype], "</td></tr>\n";
echo '<tr><th scope="row">', _('Secondary type'),"</th><td>", $company->comptype2 ? $opt_comptype[$company->comptype2] : '-', "</td></tr>\n";
echo '<tr><th scope="row">', _('Street'),"</th><td>", $company->street, "</td></tr>\n";
echo '<tr><th scope="row">', _('Zip, City'),"</th><td>", $company->zip, ' ', $company->city, "</td></tr>\n";
echo '<tr><th scope="row">', _('Country'),"</th><td>", $company->country, "</td></tr>\n";
@@ -299,7 +301,7 @@ elseif ($action == ACT_EDIT):
echo '<h2>', _('Edit Company'), "</h2>\n";
$sql = "SELECT compname, comptype, street, zip, city, country,"
$sql = "SELECT compname, comptype, comptype2, street, zip, city, country,"
. " contact, phone, email, web, customerno, contractno, remarks "
. "FROM company "
. "WHERE compid=?";
@@ -332,6 +334,21 @@ foreach ($opt_comptype as $k => $v) {
?>
</select>
</div>
<div class="mb-3">
<label for="comptype2" class="form-label"><?=_('Secondary company type')?></label>
<select name="comptype2" class="form-control">
<?php
echo '<option value="">--- kein ---', "</option>\n";
foreach ($opt_comptype as $k => $v) {
echo '<option value="', $k ,'"';
if ($company->comptype2 == $k) {
echo ' selected';
}
echo '>', $v, "</option>\n";
}
?>
</select>
</div>
<div class="mb-3">
<label for="street" class="form-label"><?=_('Street')?></label>
<input type="text" class="form-control" id="street" name="street" value="<?=$company->street ?>">
+7
View File
@@ -35,6 +35,13 @@ $g_shapedir = 'shapes';
// documents and images
$g_doc_basepath = '/var/local/yms';
$g_doc_maxsize = 1024*1024*16; // 16 MB
$g_doc_typemap = array(
'generic' => 'doc',
'manual' => 'doc',
'invoice' => 'doc',
'picture' => 'pic',
'drawing' => 'drw'
);
$g_storage_limit = 1024; // MB
+12 -1
View File
@@ -42,6 +42,17 @@ switch ($submit = form_get_action()) {
case 'insert':
// WIP New standalone document
// debug $g_message->Add(print_r($_FILES, true));
// check for possible errors
if (!isset($_FILES['files']['error']) || is_array($_FILES['files']['error'])) {
$g_error->Add(_("Invalid file upload parameters."));
$action = ACT_ADD;
break;
}
if (($_FILES['files']['error'] == UPLOAD_ERR_INI_SIZE) || ($_FILES['files']['error'] == UPLOAD_ERR_FORM_SIZE)) {
$g_error->Add(_("Exceeded filesize limit."));
$action = ACT_ADD;
break;
}
if (empty($_FILES['files']['tmp_name']) ) {
$g_warning->Add(_('No file for upload submitted. Try again by selecting a file first.'));
$action = ACT_ADD;
@@ -117,7 +128,7 @@ switch ($submit = form_get_action()) {
$p[':doctype'] = gpc_get_string($_POST, 'doctype');
$p[':filename'] = gpc_get_string($_POST, 'filename');
$p[':title'] = gpc_get_string($_POST, 'title', 40);
$p['remarks'] = gpc_get_string($_POST, 'remarks', 150);
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
db_exec_update('document', $p, 'docid');
$action = ACT_VIEW;
break;
+261 -51
View File
@@ -50,9 +50,9 @@ setlocale(LC_ALL, $g_locale);
$g_lconv = localeconv();
$g_lang = substr($g_locale, 0, 2); // short language identifier
bindtextdomain('yms', 'locale');
bind_textdomain_codeset('yms', 'UTF-8');
textdomain('yms');
bindtextdomain($g_textdomain, 'locale');
bind_textdomain_codeset($g_textdomain, 'UTF-8');
textdomain($g_textdomain);
date_default_timezone_set($g_timezone);
@@ -63,12 +63,18 @@ if ($g_scriptname != 'login.php') {
$_SESSION['prelogin'] = $_SERVER['REQUEST_URI'];
header_location('login.php');
}
$g_referrer = $_SESSION['coming_from'];
$g_referrer = $_SESSION['coming_from'] ?? $g_scriptname;
$_SESSION['coming_from'] = $g_scriptname;
}
// database
try {
$pdo = new PDO("mysql:host=$g_db_host;dbname=$g_db_schema;charset=utf8mb4", $g_db_username, $g_db_password);
} catch (PDOException $e) {
echo '<pre>';
print_r($e);
echo '</pre>';
}
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
# $pdo->query("SET lc_time_names='de_DE'");
@@ -87,6 +93,10 @@ $valid = FALSE;
// document storage
$g_doc_mimetypes = ['image/png', 'image/jpeg', 'image/svg+xml', 'application/pdf'];
// form option lists
$g_opt_all = array(-2 => _('&horbar; all &horbar;'));
$g_opt_none = array(-1 => _('&horbar; none &horbar;'));
// Initialize message system
$g_message = new Message;
$g_success = new MessageSuccess;
@@ -105,6 +115,10 @@ class Message {
function __construct() {
$this->caption = _('Information');
$this->alertclass = 'alert-info';
if (isset($_SESSION['message']['info'])) {
$this->Add($_SESSION['message']['info']);
unset($_SESSION['message']['info']);
}
}
function SetCaption($str) {
@@ -140,6 +154,10 @@ class MessageSuccess extends Message {
function __construct() {
$this->caption = _('Success');
$this->alertclass = 'alert-success';
if (isset($_SESSION['message']['succ'])) {
$this->Add($_SESSION['message']['succ']);
unset($_SESSION['message']['succ']);
}
}
}
@@ -147,6 +165,10 @@ class MessageWarning extends Message {
function __construct() {
$this->caption = _('Warning');
$this->alertclass = 'alert-warning';
if (isset($_SESSION['message']['warn'])) {
$this->Add($_SESSION['message']['warn']);
unset($_SESSION['message']['warn']);
}
}
}
@@ -154,6 +176,10 @@ class MessageError extends Message {
function __construct() {
$this->caption = _('Error');
$this->alertclass = 'alert-danger';
if (isset($_SESSION['message']['err'])) {
$this->Add($_SESSION['message']['err']);
unset($_SESSION['message']['err']);
}
}
}
@@ -209,7 +235,9 @@ class User {
// password check successful
$_SESSION['userid'] = $row->userid;
$this->loggedin = TRUE;
header_location($_SESSION['prelogin'] ?? 'index.php');
$target = $_SESSION['prelogin'] ?? 'index.php';
unset($_SESSION['prelogin']);
header_location($target);
} else {
$this->errormessage = _('Username or password invalid');
}
@@ -344,13 +372,17 @@ function db_save_filter($flt, $sno) {
}
function get_enum($enum) {
// Translate and beautify enums
// translate and beautify enums
$lookup = array(
'NULL' => _('n/a'),
'bad' => _('Bad'),
'box' => _('Box'),
'cat' => _('Catamaran'),
'completed' => _('Completed'),
'closed' => _('Closed'),
'company' => _('Company'),
'defect' => _('Defect'),
'deleted' => _('Deleted'),
'done' => _('Done'),
'drawing' => _('Drawing'),
'equipment' => _('Equipment'),
@@ -364,40 +396,52 @@ function get_enum($enum) {
'locked' => _('Locked'),
'low' => _('Low'),
'manual' => _('Manual'),
'mediim' => _('Medium'),
'medium' => _('Medium'),
'mono' => _('Monohull'),
'new' => _('New'),
'none' => _('None'),
'normal' => _('Normal'),
'ongoing' => _('Ongoing'),
'open' => _('Open'),
'paused' => _('Paused'),
'pending' => _('Pending'),
'picture' => _('Picture'),
'planned' => _('Planned'),
'precise' => _('Precise'),
'project' => _('Project'),
'repairable' => _('Repairable'),
'rough' => _('Rough'),
'storage' => _('Storage'),
'task' => _('Task'),
'tri' => _('Trimaran'),
'unknown' => _('Unknown'),
'user' => _('User'),
'vessel' => _('Vessel'),
'waiting' => _('waiting')
);
return $lookup[$enum] ?? $enum;
}
function db_load_enum($table, $column, $lookup=false, $as_dict=false) {
function db_load_enum($table, $column, $lookup=false, $as_dict=false, $check_null=false) {
// returns array of enum-values as defined in database
// if lookup is true the name lookup and translaton is applied
// if as_dict is true the enum value is returned as the array key
// if check_null is true the nullable-check is applied and returned
global $pdo;
$sql = "SELECT TRIM(TRAILING ')' FROM SUBSTRING(column_type,6)) "
$sql = "SELECT TRIM(TRAILING ')' FROM SUBSTRING(column_type,6)), is_nullable "
. "FROM information_schema.columns "
. "WHERE table_name=? AND column_name=?";
. "WHERE table_schema=DATABASE() AND table_name=? AND column_name=?";
$sth = $pdo->prepare($sql);
$sth->execute([$table, $column]);
$row = $sth->fetch(PDO::FETCH_NUM);
// for PHP < 7.4
// return array_map(function($x) { return trim($x, "'"); }, explode(',', $sth->fetchColumn()));
// return array_map(function($x) { return trim($x, "'"); }, explode(',', $row[0]));
// for PHP => 7.4
$arr = array_map(fn($x) => trim($x, "'"), explode(',', $sth->fetchColumn()));
$arr = array_map(fn($x) => trim($x, "'"), explode(',', $row[0]));
// prepend special value NULL if column is nullable
if ($check_null and $row[1] == 'YES') {
array_unshift($arr, 'NULL');
}
if ($lookup) {
if ($as_dict) {
$dict = array();
@@ -413,6 +457,98 @@ function db_load_enum($table, $column, $lookup=false, $as_dict=false) {
}
}
function db_load_taglist($objtype, $objid) {
// returns comma separated list for object
global $pdo;
global $g_error;
$taglist = '';
$sql = "SELECT GROUP_CONCAT(tagname) "
. "FROM tagref JOIN tag USING (tagid) "
. "WHERE objtype=? AND objid=?";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$objtype, $objid]);
$taglist = $sth->fetchColumn();
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
return $taglist;
}
function db_save_taglist($objtype, $objid, $taglist) {
global $pdo;
global $g_error;
// WIP
// - taglist is comma separated string
// - create not existing tags
// - update tagref: create new, remove unused
$tags = array_filter(explode(',', preg_replace('/\s+/u', '', $taglist)));
if (empty($tags)) {
// remove all from tagref
$sth = $pdo->prepare("DELETE FROM tagref WHERE objtype=? AND objid=?");
try {
$sth->execute([$objtype, $objid]);
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
} else {
// get list of non existing tags
$in = str_repeat('?,', count($tags) - 1) . '?';
$sql = "SELECT tagid, tagname FROM tag WHERE tagname IN ($in)";
$sth = $pdo->prepare($sql);
try {
$sth->execute(array_values($tags));
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
$tagids = array();
$existing = array();
foreach ($sth->fetchAll() as $row) {
$existing[] = $row['tagname'];
$tagids[] = $row['tagid'];
}
$newtags = array_diff($tags, $existing);
$sth = $pdo->prepare("INSERT INTO tag (tagname) VALUES (?)");
foreach ($newtags as $t) {
// maxlength 20 for each tag!
$sth->execute([substr($t, 0, 20)]);
$tagids[] = $pdo->LastInsertId();
}
// update references
$sql = "SELECT tagid FROM tagref WHERE objtype=? AND objid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$objtype, $objid]);
$refids = array();
$obsolete = array();
foreach ($sth->fetchAll() as $row) {
if (in_array($row['tagid'], $tagids)) {
// mark existing used references
$refids[] = $row['tagid'];
} else {
// obsolete reference
$obsolete[] = $row['tagid'];
}
}
// create missing references
$missing = array_diff($tagids, $refids);
if (! empty($missing)) {
$sql = "INSERT INTO tagref (tagid, objid, objtype) VALUES (?, ?, ?)";
$sth = $pdo->prepare($sql);
foreach ($missing as $m) {
$sth->execute([$m, $objid, $objtype]);
}
}
// remove obsolete references
if (! empty($obsolete)) {
$sql = "DELETE FROM tagref WHERE tagid=? AND objid=? and objtype=?";
$sth = $pdo->prepare($sql);
foreach ($obsolete as $o) {
$sth->execute([$o, $objid, $objtype]);
}
}
}
}
function db_get_ddtext($ddid, $ddval) {
// returns single value for dropdown
global $pdo;
@@ -428,6 +564,8 @@ function db_get_ddtext($ddid, $ddval) {
return $sth->fetchColumn();
}
// Functions to get option lists (key/value)
function db_get_options($ddid, $orderby = '', $default = NULL) {
// returns list for dropdown
global $pdo;
@@ -461,7 +599,6 @@ function db_get_opt_vessel() {
return $list;
}
// Functions to get option lists (key/value)
function db_get_opt_storage($vid) {
global $pdo;
@@ -619,10 +756,31 @@ function float_to_sql($var) {
// ========== FORM FUNCTIONS ==================================================
function form_get_action() {
if (!isset($_POST['submit'])) {
if (isset($_GET['f'])) {
$submit = $_GET['f'];
// strip parameters
/* $pos = strpos($submit, '?');
if ($pos > 2) {
$submit = substr($submit, 0, $pos);
} */
} else {
$submit = NULL;
}
} else {
$submit = $_POST['submit'];
}
if (is_array($submit)) {
$submit = key($submit);
}
return strtolower($submit);
}
function form_create_select($fieldname, $label, $optlist, $selval=NULL) {
echo '<div class="mb-3">', "\n";
echo '<label for="', $fieldname, '">', $label, "</label>\n";
echo '<select class="form-select" name="', $fieldname,'" id="', $fieldname,'">';
echo '<select class="form-select" name="', $fieldname,'" id="', $fieldname, '">', "\n";
foreach ($optlist as $k => $v) {
echo '<option value="', $k, '"';
if (isset($selval) and ($k == $selval)) {
@@ -686,60 +844,40 @@ function form_delete_buttons($script, $id, $token) {
echo "</div>\n";
}
function form_tag_assignment($script, $id) {
function form_tag_assignment($script, $id, $tags) {
echo '<tr>';
echo '<th>', _('Tags'), "</th>\n";
echo '<td>', $tags, '</td>';
echo "</tr>\n<tr>";
echo '<th>', _('Tag assignment'), "</th>\n";
echo '<td><form method="post" action="', $script, '">', "\n";
echo '<div class="form-floating">';
echo '<input type="hidden" name="id" value="', $id .'">', "\n";
echo '<label>', _('(Separate by comma)'), '</label>', "\n";
echo '<input type="text" maxlength="80" class="form-control" name="tagstring">', "\n";
echo '<input type="text" maxlength="80" class="form-control" name="tagstring" value="', $tags, '">', "\n";
echo '<input type="submit">', "\n";
echo "</div></form></td></td>\n";
echo "</tr>";
}
// ========== COMMON FUNCTIONS ================================================
function header_location($location) {
header("Location: $location");
exit;
function filter_create_select($fieldname, $label, $optlist, $selval=NULL) {
echo '<label for="', $fieldname,'">', $label,'</label>', "\n";
echo '<select id="', $fieldname, '" name="', $fieldname, '">', "\n";
foreach ($optlist as $k => $v) {
echo '<option value="', $k, '"';
if ($k == $selval) {
echo ' selected';
}
echo '>', $v, '</option>', "\n";
}
echo "</select>\n";
}
function form_get_action() {
if (!isset($_POST['submit'])) {
if (isset($_GET['f'])) {
$submit = $_GET['f'];
// strip parameters
/* $pos = strpos($submit, '?');
if ($pos > 2) {
$submit = substr($submit, 0, $pos);
} */
} else {
$submit = NULL;
}
} else {
$submit = $_POST['submit'];
}
if (is_array($submit)) {
$submit = key($submit);
}
return strtolower($submit);
}
function get_color_brightness($color) {
// returns a value between 0 and 1
// color is a 6 char hex string
list($red, $green, $blue) = array_map('hexdec', str_split($color, 2));
$red = $red / 255 * 0.2126;
$green = $green / 255 * 0.7152;
$blue = $blue / 255 * 0.0722;
return $red + $green + $blue;
}
// ========== GPC FUNCTIONS ===================================================
function gpc_get_string(&$GPC, $varname, $maxlen = NULL, $default = NULL) {
// TODO Parameter nullval: single value or array of values which considered as null
// Default value for nullval is "-1"
if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) {
return $default;
}
@@ -799,6 +937,15 @@ function gpc_get_bool(&$GPC, $varname, $default = FALSE) {
}
function gpc_get_date(&$GPC, $varname, $default = NULL) {
// TODO improve
if (!isset($GPC[$varname]) || $GPC[$varname] == '') {
return $default;
}
return $GPC[$varname];
}
function gpc_get_datetime(&$GPC, $varname, $default = NULL) {
// TODO improve
if (!isset($GPC[$varname]) || $GPC[$varname] == '') {
return $default;
}
@@ -829,6 +976,8 @@ function gpc_get_enum(&$GPC, $varname, $values, $default = NULL) {
return $GPC[$varname];
}
// ========== FORMAT FUNCTIONS ================================================
function format_float($val, $decimals = 2, $suffix = '') {
global $g_lconv;
if (!isset($val) || $val == '') {
@@ -910,6 +1059,67 @@ function format_measurement($n, $unit, $v1, $v2, $v3) {
return $m;
}
// ========== COMMON FUNCTIONS ================================================
function header_location($location, $message=NULL) {
if (is_array($message)) {
$valid_keys = array('succ', 'info', 'warn', 'err');
foreach ($message as $k => $v) {
if (in_array($k, $valid_keys)) {
$_SESSION['message'][$k] = $v;
}
}
}
header("Location: $location");
exit;
}
function pgettext($context, $msgid) {
// implement missing function
global $g_textdomain;
$ctxstr = "{$context}\004{$msgid}";
$translation = dcgettext($g_textdomain, $ctxstr, LC_MESSAGES);
if ($translation == $ctxstr) {
return $msgid;
} else {
return $translation;
}
}
function get_color_brightness($color, $default=0.5) {
// returns a value between 0 and 1
// color is a 6 char hex string
if (strlen($color) != 6) {
return $default;
}
list($red, $green, $blue) = array_map('hexdec', str_split($color, 2));
$red = $red / 255 * 0.2126;
$green = $green / 255 * 0.7152;
$blue = $blue / 255 * 0.0722;
return $red + $green + $blue;
}
function page_caption_search($caption) {
// print page caption with searchbox
?>
<div class="row align-items-center">
<div class="col">
<h1><?=$caption?></h1>
</div>
<div class="col-4">
<form class="form-inline" method="post" action="search.php">
<div class="input-group input-group-sm">
<input name="needle" type="search" class="form-control" placeholder="<?=_('Search')?>">
<div class="input-group-append">
<button class="btn btn-sm btn-primary" type="submit"><i class="bi bi-search"></i></button>
</div>
</div>
</form>
</div>
</div>
<?php
}
function get_pagination($script, $param, $page, $lastpage, $small=false) {
// no direct output, returns string for multiple output
+7
View File
@@ -9,6 +9,13 @@
<link href="bootstrap/bootstrap-icons.min.css" rel="stylesheet">
<script src="bootstrap/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="default.css">
<?php
if (isset($GLOBALS['local_script'])) {
echo '<script type="text/javascript">', "\n";
echo $GLOBALS['local_script'];
echo "</script>\n";
}
?>
</head>
<body>
<div class="container-xxl">
+10 -1
View File
@@ -138,6 +138,14 @@ $sql = "SELECT vesselname, model, loa, lwl, beam, draught, draught_min,"
$sth = $pdo->prepare($sql);
$sth->execute([$vid]);
$vessel = $sth->fetch(PDO::FETCH_OBJ);
// Show remarks first
if (strlen($vessel->remarks) > 0) {
echo "<p>";
echo $vessel->remarks;
echo "</p>\n";
}
// get vessel shape
// test for predefined base shape
$shapefilepath = dirname(__FILE__).'/'.$g_shapedir.'/'.$vessel->shapefile;
@@ -146,7 +154,8 @@ if (isset($vessel->shapefile) and file_exists($shapefilepath)) {
} else {
// use internal default shape
$baseshape = <<<EOT
<svg version="1.1" width="1024" height="350" viewBox="0 0 1024 350" id="svg1">
<svg version="1.1" width="1024" height="350" viewBox="0 0 1024 350" id="svg1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="g1">
<path id="path1" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:8, 4, 2, 4;stroke-dashoffset:0;stroke-opacity:1" d="M 3.3e-6,174.91172 1023.9982,174.90837" />
<path id="path2" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="m 1.1002728,174.9708 c 0,0 0.150828,-90.157538 0.02448,-103.853791 C 66.951611,46.573152 247.6267,3.4573666 430.56326,3.8276086 670.30694,4.3128215 758.66035,44.913257 838.18466,74.965511 917.70898,105.01776 1022.8821,175.00227 1022.8821,175.00227" />
+16 -27
View File
@@ -1,7 +1,7 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
* Copyright (C) 2024-2025 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
@@ -17,6 +17,7 @@ $opt_user = array();
foreach ($sth->fetchAll() as $row) {
$opt_user[$row['userid']] = $row['displayname'];
}
$opt_state = db_load_enum('project', 'projstate', true, true);
// ========== ACTIONS START ===================================================
@@ -37,11 +38,11 @@ switch ($submit = form_get_action()) {
break;
case 'insert':
$p['vid'] = $user->id;
$p[':vid'] = $user->vid;
$p[':projname'] = gpc_get_string($_POST, 'projname');
$p[':responsible'] = gpc_get_int($_POST, 'responsible');
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
$id = db_exec_insert('company', $p);
$id = db_exec_insert('project', $p);
$action = ACT_VIEW;
break;
@@ -50,6 +51,7 @@ switch ($submit = form_get_action()) {
$p[':projname'] = gpc_get_string($_POST, 'projname');
$p[':startdate'] = gpc_get_date($_POST, 'startdate');
$p[':duration'] = gpc_get_int($_POST, 'duration');
$p[':projstate'] = gpc_get_string($_POST, 'projstate');
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
db_exec_update('project', $p, 'projid');
$action = ACT_VIEW;
@@ -121,9 +123,10 @@ echo "<h1>", _('Generic Tasks'), "</h1>\n";
echo "<p>", _('Tasks not assigned to any project'), "</p>\n";
$sql = "SELECT taskid, taskname "
. "FROM task "
. "WHERE projid IS NULL "
. "WHERE vid=? AND projid IS NULL "
. "ORDER BY taskid";
$sth = $pdo->query($sql);
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
@@ -156,16 +159,9 @@ echo '<h2>', _('Add Project'), "</h2>\n";
<label for="projname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="projname" name="projname">
</div>
<div class="mb-3">
<label for="responsible" class="form-label"><?=_('Responsible')?></label>
<select name="responsible" class="form-control">
<?php
foreach ($opt_user as $k => $v) {
echo '<option value="', $k ,'">', $v, "</option>\n";
}
form_create_select('responsible', _('Responsible'), $opt_user, $project->responsible);
?>
</select>
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"></textarea>
@@ -178,7 +174,7 @@ foreach ($opt_user as $k => $v) {
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT projname, startdate, duration, responsible, remarks "
$sql = "SELECT projname, startdate, duration, responsible, projstate, remarks "
. "FROM project "
. "WHERE projid=?";
$sth = $pdo->prepare($sql);
@@ -190,6 +186,7 @@ echo '<tr><th scope="row" style="width:20%">', _('Name'),"</th><td>", $project->
echo '<tr><th scope="row">', _('Responsible'),"</th><td>", $opt_user[$project->responsible], "</td></tr>\n";
echo '<tr><th scope="row">', _('Start date'),"</th><td>", $project->startdate, "</td></tr>\n";
echo '<tr><th scope="row">', _('Duration'),"</th><td>", $project->duration, "</td></tr>\n";
echo '<tr><th scope="row">', _('State'),"</th><td>", $project->projstate, "</td></tr>\n";
echo '<tr><th scope="row">', _('Remarks'),"</th><td>", $project->remarks, "</td></tr>\n";
echo "</table>\n";
@@ -223,7 +220,7 @@ elseif ($action == ACT_EDIT):
echo '<h2>', _('Edit Project'), "</h2>\n";
$sql = "SELECT projname, responsible, startdate, duration, remarks "
$sql = "SELECT projname, responsible, startdate, duration, projstate, remarks "
. "FROM project "
. "WHERE projid=?";
$sth = $pdo->prepare($sql);
@@ -237,20 +234,9 @@ $project = $sth->fetch(PDO::FETCH_OBJ);
<label for="projname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="projname" name="projname" value="<?=$project->projname ?>">
</div>
<div class="mb-3">
<label for="responsible" class="form-label"><?=_('Responsible')?></label>
<select name="responsible" class="form-control">
<?php
foreach ($opt_user as $k => $v) {
echo '<option value="', $k ,'"';
if ($project->responsible == $k) {
echo ' selected';
}
echo '>', $v, "</option>\n";
}
form_create_select('responsible', _('Responsible'), $opt_user, $project->responsible);
?>
</select>
</div>
<div class="mb-3">
<label for="startdate"><?=_('Startdate')?></label>
<input type="date" class="form-control" id="startdate" name="startdate" value="<?=$project->startdate ?>">
@@ -259,6 +245,9 @@ foreach ($opt_user as $k => $v) {
<label for="duration"><?=_('Duration, days')?></label>
<input type="number" class="form-control" id="duration" name="duration" min="1" value="<?=$project->duration ?>">
</div>
<?php
form_create_select('projstate', _('Status'), $opt_state, $project->projstate);
?>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$project->remarks ?></textarea>
+1 -1
View File
@@ -1,7 +1,7 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
* Copyright (C) 2024-2025 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/