Timecard v1.0.0

This commit is contained in:
kemasama 2022-05-22 15:22:49 +09:00
parent 4b429c2429
commit a86fe2a85b
16 changed files with 1113 additions and 15 deletions

View File

@ -8,5 +8,7 @@ return [
"password" => ""
],
"admin-password" => "admin",
"canonical" => "http://localhost/timecard/",
"heads" => [],
];

7
css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,8 @@
<?php
ini_set("display_erros", "on");
require_once __DIR__ . '/provide/autoload.php';
$boot = new BootLoader(__DIR__);
$boot->run();

View File

@ -8,16 +8,3 @@
require_once __DIR__ . '/ClassLoader.php';
spl_autoload_register(array("ClassLoaderXProvide", "loadClass"));
$config = require_once __DIR__ . '/../config.php';
$db = new IDB();
if (!$db->Connect($config["mysql"]["hostname"],
$config["mysql"]["dbname"],
$config["mysql"]["username"],
$config["mysql"]["password"])
)
{
echo 'can not connect to mysql server.';
exit;
}
$pdo = $db->getDB();

View File

@ -0,0 +1,162 @@
<?php
/***
* Copyright (c) 2022 DevRas
*
*/
class BootLoader
{
public function __construct($root)
{
$this->root = $root;
$this->session = new UserSession();
$this->model = new Template($this->root . "/template");
}
protected $root;
protected $pdo;
protected $cards;
protected $config;
protected $session;
protected $model;
public function run()
{
try {
$this->InitPDO();
$this->cards = new Timecard($this->pdo);
$this->cards->InitTables();
$user = new User($this->pdo);
$isAdmin = false;
$loginUser = [];
$works = [];
$page = filter_input(INPUT_GET, "p") ?? "home";
if ($user->hasLogout())
{
$this->session->setUsername(null);
header("Location: ?login");
exit;
}
$logged = $this->session->isLogged();
if (!$logged)
{
$loginUser = $user->hasLogin();
if ($loginUser)
{
$this->session->setUsername($loginUser["username"]);
$logged = true;
} else
{
$this->model->viewModel("login", [
"method" => "POST",
"canonical" => $this->config["canonical"],
"config" => $this->config
]);
exit;
}
}
$loginUser = $user->getUser($this->session->getUsername());
if (!$loginUser)
{
throw new \RuntimeException("不正なユーザーです");
}
$isAdmin = array_search($this->session->getUsername(), $this->config["admin_users"]) !== false;
if ($page == "passwd")
{
if ($user->hasUpdatePassword($loginUser))
{
header("Location: ?p=home");
exit;
}
$this->model->viewModel("passwd", [
"username" => $this->session->getUsername(),
"config" => $this->config,
]);
exit;
}
if ($page == "create" && $isAdmin)
{
if ($user->hasCreate())
{
header("Location: ?p=home");
exit;
}
$this->model->viewModel("create", [
"config" => $this->config,
]);
exit;
}
if ($page == "view")
{
$id = filter_input(INPUT_GET, "id");
$loginUser = $user->getUserById($id);
if (!$loginUser)
{
throw new \RuntimeException("不正なユーザーです");
}
}
$result = $this->cards->hasCard($loginUser["id"], $isAdmin);
$works = $this->cards->SelectTimes($loginUser["id"]);
$lastCard = $this->cards->getLastInsert($loginUser["id"]);
$users = $this->cards->getUsers();
$this->model->viewModel("view", [
"logged" => $logged,
"users" => $users,
"user" => $loginUser,
"works" => $works,
"canonical" => $this->config["canonical"],
"config" => $this->config,
"addCard" => $result,
"lastCard" => $lastCard,
"isAdmin" => $isAdmin,
]);
} catch (\RuntimeException $e)
{
http_response_code(401);
$result = $this->model->viewModel("error", [
"exception" => $e,
"message" => $e->getMessage(),
"config" => $this->config,
]);
if (!$result)
{
echo $e->getMessage();
exit;
}
}
}
protected function InitPDO()
{
$config = require_once $this->root . '/config.php';
$db = new IDB();
if (!$db->Connect($config["mysql"]["hostname"],
$config["mysql"]["dbname"],
$config["mysql"]["username"],
$config["mysql"]["password"])
)
{
throw new \RuntimeException('can not connect to mysql server.');
}
$this->pdo = $db->getDB();
$this->config = $config;
}
}

View File

@ -0,0 +1,11 @@
<?php
/***
* Copyright (c) 2022 DevRas
*
*/
class CardType
{
public const START = 1;
public const END = 2;
}

View File

@ -1,4 +1,4 @@
<?php
<?php
class IDB {
public function __construct() {

View File

@ -0,0 +1,29 @@
<?php
/***
* Copyright (c) 2022 DevRas
*
*/
class Template
{
public function __construct($root)
{
$this->root = $root;
}
protected $root;
public function viewModel($model, $args = [])
{
$args["__LOADER__"] = $this;
$path = $this->root . DIRECTORY_SEPARATOR . $model . ".php";
if (!file_exists($path))
{
return false;
}
return @include $path;
}
}

View File

@ -1,4 +1,8 @@
<?php
/***
* Copyright (c) 2022 DevRas
*
*/
class Timecard
{
@ -9,7 +13,218 @@ class Timecard
protected $pdo;
public function InsertTime()
public function InitTables()
{
try {
$pdo = $this->pdo;
$pdo->query("CREATE TABLE IF NOT EXISTS users(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, password VARCHAR(64) NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);");
$pdo->query("CREATE TABLE IF NOT EXISTS cards(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, uid INT NOT NULL, startTime DATETIME, endTime DATETIME, validate INT NOT NULL DEFAULT 0);");
} catch (\PDOException $e)
{
throw new \RuntimeException("データベースの初期化中にエラーが発生しました。");
}
}
public function getUsers()
{
try {
$smt = $this->pdo->prepare("SELECT * FROM users");
$smt->execute([
]);
$buf = array();
while ( $row = $smt->fetch() )
{
$buf[] = array(
"id" => $row["id"],
"username" => $row["username"],
"created_at" => $row["created_at"],
);
}
return $buf;
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所getUsers");
}
}
public function hasCard($id, $admin)
{
$uid = filter_input(INPUT_POST, "uid");
$mode = filter_input(INPUT_POST, "reg");
$date = filter_input(INPUT_POST, "date");
if (!$uid || !$mode)
{
return false;
}
if ($uid < 0)
{
return false;
}
if (!$admin && $id != $uid)
{
return false;
}
if (!$admin)
{
$date = "";
}
switch ($mode)
{
case "auto":
$this->InsertTime($uid, $date);
break;
case "start":
$this->InsertTimeManual(CardType::START, $uid, $date);
break;
case "end":
$this->InsertTimeManual(CardType::END, $uid, $date);
break;
default:
break;
}
return true;
}
public function SelectTimes($uid)
{
try {
$today = ((int) date("d")) - 1;
$dayCount = (int) date("t");
$startTime = date("Y-m-d 00:00:00", strtotime(sprintf("-%ddays", $today)));
$endTime = date("Y-m-d 00:00:00", strtotime(sprintf("+%ddays", $dayCount - $today)));
$smt = $this->pdo->prepare("SELECT * FROM cards WHERE startTime > ? AND endTime < ? AND uid=?;");
$smt->execute([
$startTime,
$endTime,
$uid
]);
$buf = array();
while ($row = $smt->fetch())
{
$start = strtotime($row["startTime"]);
$end = strtotime($row["endTime"]);
$diff = $end - $start;
$workTime = $diff / 60 / 60;
$workHour = floor($workTime);
$workMinutes = floor(($workTime - $workHour) * 60);
$buf[] = array(
"startTime" => $row["startTime"],
"endTime" => $row["endTime"],
"validate" => $row["validate"],
"id" => $row["id"],
"workTime" => $workTime,
"workHour" => $workHour,
"workMinutes" => $workMinutes,
);
}
return $buf;
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所selectTimes");
}
}
public function InsertTime($uid, $date)
{
try {
$smt;
$lix = $this->getLastInsert($uid);
$now = date("Y-m-d H:i:s");
if (strtotime($date))
{
$now = date("Y-m-d H:i:s", strtotime($date));
}
if ( !$lix )
{
$smt = $this->pdo->prepare("INSERT INTO cards(uid, startTime) VALUES(?, ?);");
$smt->execute([
$uid,
$now
]);
} else if ( $lix )
{
$smt = $this->pdo->prepare("UPDATE cards SET endTime = ?, validate = 1 WHERE id = ?;");
$smt->execute([
$now,
$lix["id"]
]);
} else {
throw new \RuntimeException("打刻できませんでした。原因:不明な操作");
}
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所insertTime");
}
}
public function InsertTimeManual($type, $uid, $date)
{
try {
$smt;
$lix = $this->getLastInsert($uid);
$now = date("Y-m-d H:i:s");
if (strtotime($date))
{
$now = date("Y-m-d H:i:s", strtotime($date));
}
if ( !$lix && $type == CardType::START )
{
$smt = $this->pdo->prepare("INSERT INTO cards(uid, startTime) VALUES(?, ?);");
$smt->execute([
$uid,
$now
]);
} else if ( $lix && $type == CardType::END )
{
$smt = $this->pdo->prepare("UPDATE cards SET endTime = ?, validate = 1 WHERE id = ?;");
$smt->execute([
$now,
$lix["id"]
]);
} else {
throw new \RuntimeException("打刻できませんでした。原因:始業が登録済みで始業をした。または、終業済みで終業をした。または、不明な操作。");
}
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所insertTime");
}
}
public function getLastInsert($uid)
{
try {
$smt = $this->pdo->prepare("SELECT * FROM cards WHERE uid = ? AND validate = 0 ORDER BY id DESC LIMIT 1;");
$smt->execute([
$uid
]);
return $smt->fetch();
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所lastInsert");
}
}
}

176
provide/classes/User.php Normal file
View File

@ -0,0 +1,176 @@
<?php
/***
* Copyright (c) 2022 DevRas
*
*/
class User
{
public function __construct($pdo)
{
$this->pdo = $pdo;
}
protected $pdo;
public function formalPassword($password)
{
return hash("sha256", $password);
}
public function hasLogout()
{
$filter = filter_input(INPUT_GET, "logout");
if ($filter)
{
return true;
} else {
return false;
}
}
public function hasLogin()
{
$username = filter_input(INPUT_POST, "username");
$password = filter_input(INPUT_POST, "password");
if (!$username || !$password)
{
return false;
}
$result = $this->Login($username, $password);
return $result;
}
public function hasUpdatePassword()
{
$username = filter_input(INPUT_POST, "username");
$password = filter_input(INPUT_POST, "password");
$newPassword = filter_input(INPUT_POST, "newPassword");
if (!$username || !$password || !$newPassword)
{
return false;
}
$currentUser = $this->Login($username, $password);
if (!$currentUser)
{
return false;
}
$result = $this->updatePassword($currentUser, $newPassword);
return $result;
}
public function hasCreate()
{
$username = filter_input(INPUT_POST, "username");
$password = filter_input(INPUT_POST, "password");
$mode = filter_input(INPUT_POST, "mode");
if (!$username || !$password || !$mode)
{
return false;
}
$result = $this->Create($username, $password);
return $result;
}
public function updatePassword($currentUser, $newPassword)
{
try {
$formal = $this->formalPassword($newPassword);
$smt = $this->pdo->prepare("UPDATE users SET password=? WHERE id=?");
$smt->execute([
$formal,
$currentUser["id"]
]);
return true;
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。パスワードの更新に失敗しました。");
}
}
public function Login($username, $password)
{
try {
$formal = $this->formalPassword($password);
$smt = $this->pdo->prepare("SELECT * FROM users WHERE username=? AND password=?;");
$smt->execute([
$username,
$formal
]);
return $smt->fetch();
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所UserLogin");
}
}
public function Create($username, $password)
{
$user = $this->getUser($username);
if ($user)
{
throw new \RuntimeException("操作を続行できません。そのユーザー名は既に存在します。");
}
try {
$smt = $this->pdo->prepare("INSERT INTO users(username, password) VALUES(?, ?);");
$formal = $this->formalPassword($password);
$smt->execute([
$username,
$formal
]);
return true;
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所createUser");
}
}
public function getUser($username)
{
try {
$smt = $this->pdo->prepare("SELECT * FROM users WHERE username=?");
$smt->execute([
$username
]);
return $smt->fetch();
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所getUser");
}
}
public function getUserById($id)
{
try {
$smt = $this->pdo->prepare("SELECT * FROM users WHERE id=?");
$smt->execute([
$id
]);
return $smt->fetch();
} catch (\PDOException $e)
{
throw new \RuntimeException("SQLエラーが発生しました。発生箇所getUser");
}
}
}

View File

@ -0,0 +1,35 @@
<?php
/***
* Copyright (c) 2022 DevRas
*
*/
class UserSession
{
public function __construct()
{
@session_start();
}
public $SessionName = "devras_timecard";
public function isLogged()
{
if (!isset($_SESSION[$this->SessionName]))
{
return false;
}
return !empty($_SESSION[$this->SessionName]);
}
public function getUsername()
{
return $_SESSION[$this->SessionName];
}
public function setUsername($value)
{
$_SESSION[$this->SessionName] = $value;
}
}

78
template/create.php Normal file
View File

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>ユーザー作成 | タイムカード</title>
<link rel="canonical" href="<?php echo $args["canonical"]; ?>" />
<link rel="stylesheet" href="<?php echo $args["canonical"]; ?>css/bootstrap.min.css" />
<?php foreach ($args["config"]["heads"] as $key => $val): ?>
<?php echo $val; ?>
<?php endforeach; ?>
</head>
<body>
<div class="container">
<h2>タイムカード</h2>
</div>
<div class="container">
<h3>ユーザー作成</h3>
<p>
作成するユーザー名、パスワードを入力後作成ボタンを押してください。
</p>
<form class="form" method="POST">
<div class="form-group row">
<div class="col-md-2">
<label for="username" class="form-label">ユーザー名</label>
</div>
<div class="col-md-7">
<input type="text" value="" class="form-control" name="username" id="username" />
</div>
<div class="col-md-3 form-text">
ユーザー名を入力してください。
</div>
</div>
<div class="form-group row">
<div class="col-md-2">
<label for="password" class="form-label">パスワード</label>
</div>
<div class="col-md-7">
<input type="password" value="" class="form-control" name="password" id="password" />
</div>
<div class="col-md-3 form-text">
パスワードを入力してください。
</div>
</div>
<input type="hidden" name="mode" value="create" />
<div class="form-group row">
<div class="col-md-2">
</div>
<div class="col-md-7">
<button class="btn btn-primary" type="submit">作成</button>
</div>
<div class="col-md-3 form-text">
</div>
</div>
</form>
</div>
<div class="container">
<footer class="footer">
<div class="container text-center">
<p class="text-muted">
Copyright &copy; 2022 <a href="https://devras.net">DevRas</a> All Rights Reserved.
</p>
<p class="text-muted">
TimeCard v1.0.0
<a href="https://github.com/kemasama/Timecard">github</a>
</p>
</div>
</footer>
</div>
</body>
</html>

49
template/error.php Normal file
View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>エラー | タイムカード</title>
<link rel="canonical" href="<?php echo $args["config"]["canonical"]; ?>" />
<link rel="stylesheet" href="<?php echo $args["config"]["canonical"]; ?>css/bootstrap.min.css" />
<?php foreach ($args["config"]["heads"] as $key => $val): ?>
<?php echo $val; ?>
<?php endforeach; ?>
</head>
<body>
<div class="container">
<h2>タイムカード</h2>
<p>
<a href="?logout=1">ログアウト</a>
</p>
</div>
<div class="container">
<h3>エラー</h3>
<p>
サービスの処理中にエラーが発生しました。<br />
ホームに戻るには<a href="<?php echo $args["config"]["canonical"]; ?>">こちら</a>をクリックしてください。<br />
</p>
<code>
<?php echo $args["message"]; ?>
</code>
<p>
エラーが続けて発生する場合は、サーバー管理者にお問い合わせください。
</p>
</div>
<div class="container">
<footer class="footer">
<div class="container text-center">
<p class="text-muted">
Copyright &copy; 2022 <a href="https://devras.net">DevRas</a> All Rights Reserved.
</p>
<p class="text-muted">
TimeCard v1.0.0
<a href="https://github.com/kemasama/Timecard">github</a>
</p>
</div>
</footer>
</div>
</body>
</html>

76
template/login.php Normal file
View File

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>ログイン | タイムカード</title>
<link rel="canonical" href="<?php echo $args["canonical"]; ?>" />
<link rel="stylesheet" href="<?php echo $args["canonical"]; ?>css/bootstrap.min.css" />
<?php foreach ($args["config"]["heads"] as $key => $val): ?>
<?php echo $val; ?>
<?php endforeach; ?>
</head>
<body>
<div class="container">
<h2>タイムカード</h2>
</div>
<div class="container">
<h3>ログイン</h3>
<p>
ログインするユーザー名、パスワードを入力後ログインボタンを押してください。
</p>
<form class="form" method="POST">
<div class="form-group row">
<div class="col-md-2">
<label for="username" class="form-label">ユーザー名</label>
</div>
<div class="col-md-7">
<input type="text" value="" class="form-control" name="username" id="username" />
</div>
<div class="col-md-3 form-text">
ユーザー名を入力してください。
</div>
</div>
<div class="form-group row">
<div class="col-md-2">
<label for="password" class="form-label">パスワード</label>
</div>
<div class="col-md-7">
<input type="password" value="" class="form-control" name="password" id="password" />
</div>
<div class="col-md-3 form-text">
パスワードを入力してください。
</div>
</div>
<div class="form-group row">
<div class="col-md-2">
</div>
<div class="col-md-7">
<button class="btn btn-primary" type="submit">ログイン</button>
</div>
<div class="col-md-3 form-text">
</div>
</div>
</form>
</div>
<div class="container">
<footer class="footer">
<div class="container text-center">
<p class="text-muted">
Copyright &copy; 2022 <a href="https://devras.net">DevRas</a> All Rights Reserved.
</p>
<p class="text-muted">
TimeCard v1.0.0
<a href="https://github.com/kemasama/Timecard">github</a>
</p>
</div>
</footer>
</div>
</body>
</html>

89
template/passwd.php Normal file
View File

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>パスワード変更 | タイムカード</title>
<link rel="canonical" href="<?php echo $args["canonical"]; ?>" />
<link rel="stylesheet" href="<?php echo $args["canonical"]; ?>css/bootstrap.min.css" />
<?php foreach ($args["config"]["heads"] as $key => $val): ?>
<?php echo $val; ?>
<?php endforeach; ?>
</head>
<body>
<div class="container">
<h2>タイムカード</h2>
</div>
<div class="container">
<h3>パスワード変更</h3>
<p>
ユーザー名と現在のパスワード、新しいパスワードを入力して変更ボタンをクリックしてください。
</p>
<form class="form" method="POST">
<div class="form-group row">
<div class="col-md-2">
<label for="username" class="form-label">ユーザー名</label>
</div>
<div class="col-md-7">
<input type="text" value="<?php echo $args["username"]; ?>" class="form-control" name="username" id="username" />
</div>
<div class="col-md-3 form-text">
ユーザー名を入力してください。
</div>
</div>
<div class="form-group row">
<div class="col-md-2">
<label for="password" class="form-label">現在パスワード</label>
</div>
<div class="col-md-7">
<input type="password" value="" class="form-control" name="password" id="password" />
</div>
<div class="col-md-3 form-text">
現在のパスワードを入力してください。
</div>
</div>
<div class="form-group row">
<div class="col-md-2">
<label for="newpassword" class="form-label">新しいパスワード</label>
</div>
<div class="col-md-7">
<input type="password" value="" class="form-control" name="newPassword" id="newpassword" />
</div>
<div class="col-md-3 form-text">
新しいパスワードを入力してください。
</div>
</div>
<div class="form-group row">
<div class="col-md-2">
</div>
<div class="col-md-7">
<button class="btn btn-primary" type="submit">変更</button>
</div>
<div class="col-md-3 form-text">
</div>
</div>
</form>
</div>
<div class="container">
<footer class="footer">
<div class="container text-center">
<p class="text-muted">
Copyright &copy; 2022 <a href="https://devras.net">DevRas</a> All Rights Reserved.
</p>
<p class="text-muted">
TimeCard v1.0.0
<a href="https://github.com/kemasama/Timecard">github</a>
</p>
</div>
</footer>
</div>
</body>
</html>

178
template/view.php Normal file
View File

@ -0,0 +1,178 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>タイムカード</title>
<link rel="canonical" href="<?php echo $args["canonical"]; ?>" />
<link rel="stylesheet" href="<?php echo $args["canonical"]; ?>css/bootstrap.min.css" />
<?php foreach ($args["config"]["heads"] as $key => $val): ?>
<?php echo $val; ?>
<?php endforeach; ?>
<!-- Version 1.0.0 -->
</head>
<body>
<div class="container">
<h2>タイムカード</h2>
<p>
<a href="?logout=1">ログアウト</a>
<?php if($args["isAdmin"]): ?>
<a href="?p=create">ユーザー作成</a>
<?php endif; ?>
<a href="?p=passwd">パスワード変更</a>
</p>
<p class="text-info">
ようこそ、
<?php echo $args["user"]["username"]; ?>
さん!
</p>
</div>
<div class="container mt-3">
<?php if($args["addCard"]): ?>
<p class="text-danger">タイムカードを登録しました。</p>
<?php endif; ?>
<form class="form" method="POST">
<?php if($args["isAdmin"]): ?>
<div class="form-group row">
<div class="col-md-2">
<label for="username" class="form-label">ユーザー名</label>
</div>
<div class="col-md-7">
<select name="uid" id="username" class="form-select">
<option value="-1" disabled> 選択してください </option>
<?php foreach($args["users"] as $user): ?>
<?php if($user["id"] == $args["user"]["id"]): ?>
<option value="<?php echo $user["id"]; ?>" selected><?php echo $user["username"]; ?></option>
<?php else: ?>
<option value="<?php echo $user["id"]; ?>"><?php echo $user["username"]; ?></option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3 form-text">
タイムカードを登録したいユーザーを選択してください
</div>
</div>
<?php else: ?>
<input type="hidden" name="uid" value="<?php echo $args["user"]["id"]; ?>" />
<?php endif; ?>
<div class="form-group row">
<div class="col-md-2">
打刻時刻
</div>
<div class="col-md-7">
<?php if($args["isAdmin"]): ?>
<input class="form-control" type="datetime" name="date" value="<?php echo date("Y-m-d H:i:s"); ?>" />
<?php else: ?>
<input class="form-control" type="datetime" name="date" value="<?php echo date("Y-m-d H:i:s"); ?>" readonly />
<?php endif; ?>
</div>
<div class="col-md-3 form-text">
打刻する時間になります。通常はそのままで問題ありません。
</div>
</div>
<div class="form-group row">
<div class="col-md-2">
</div>
<div class="col-md-7">
<button class="btn btn-primary" type="submit" name="reg" value="start">始業</button>
<button class="btn btn-primary" type="submit" name="reg" value="end">終業</button>
<button class="btn btn-primary" type="submit" name="reg" value="auto">登録</button>
</div>
<div class="col-md-3 form-text">
</div>
</div>
</form>
</div>
<?php if($args["isAdmin"]): ?>
<div class="container mt-3">
<form class="form" method="GET">
<div class="form-group row">
<div class="col-md-6">
<select name="id" id="username" class="form-select">
<?php foreach($args["users"] as $user): ?>
<?php if($user["id"] == $args["user"]["id"]): ?>
<option value="<?php echo $user["id"]; ?>" selected><?php echo $user["username"]; ?></option>
<?php else: ?>
<option value="<?php echo $user["id"]; ?>"><?php echo $user["username"]; ?></option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<button class="btn btn-success" type="submit">移動</button>
</div>
<div class="col-md-3 text-muted">
選択したユーザーのタイムカードを開きます。
</div>
</div>
<input type="hidden" name="p" value="view" />
</form>
</div>
<?php endif; ?>
<hr />
<?php if($args["logged"]): ?>
<div class="container mt-3">
<?php if(empty($args["works"]) && !$args["lastCard"]): ?>
<p class="text-danger">タイムカードは登録されていません。</p>
<?php else: ?>
<?php $hours = 0; $minutes = 0; ?>
<div class="table-responsive">
<table class="table table-hover table-bordered">
<tr>
<th>始業</th>
<th>終業</th>
<th>実働時間</th>
</tr>
<?php if($args["lastCard"] && $args["lastCard"]["endTime"] == NULL): ?>
<tr class="timecard">
<td><?php echo $args["lastCard"]["startTime"]; ?></td>
<td> - </td>
<td> - </td>
</tr>
<?php endif; ?>
<?php foreach ($args["works"] as $k => $v): ?>
<tr>
<td><?php echo $v["startTime"]; ?></td>
<td><?php echo $v["endTime"]; ?></td>
<td><?php echo $v["workHour"]; ?>h <?php echo $v["workMinutes"]; ?>m</td>
</tr>
<?php $hours += $v["workHour"]; ?>
<?php $minutes += $v["workMinutes"]; ?>
<?php if ($minutes >= 60) {
$hours += 1;
$minutes -= 60;
} ?>
<?php endforeach; ?>
<tr class="mt-1">
<th>合計</th>
<td><?php echo $hours; ?>h</td>
<td><?php echo $minutes; ?>m</td>
</tr>
</table>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="container">
<footer class="footer">
<div class="container text-center">
<p class="text-muted">
Copyright &copy; 2022 <a href="https://devras.net">DevRas</a> All Rights Reserved.
</p>
<p class="text-muted">
TimeCard v1.0.0
<a href="https://github.com/kemasama/Timecard">github</a>
</p>
</div>
</footer>
</div>
</body>
</html>