done. ready!

This commit is contained in:
nemunaire 2018-07-20 05:04:06 +02:00
parent a517a2201f
commit b3abc0d434
12 changed files with 326 additions and 111 deletions

View File

@ -11,14 +11,17 @@ import (
)
func init() {
router.GET("/api/checks/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.GET("/api/checks", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.GetChecks()
}))
router.DELETE("/api/checks", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.ClearChecks()
}))
router.GET("/api/items/:iid/checks/", apiHandler(itemHandler(func (item ckh.Item, _ []byte) (interface{}, error) {
router.GET("/api/items/:iid/checks", apiHandler(itemHandler(func (item ckh.Item, _ []byte) (interface{}, error) {
return item.GetChecks()
})))
router.POST("/api/items/:iid/checks/", apiHandler(itemHandler(newCheck)))
router.POST("/api/items/:iid/checks", apiHandler(itemHandler(newCheck)))
router.GET("/api/items/:iid/checks/:cid", apiHandler(checkHandler(func (check ckh.Check, _ ckh.Item, _ []byte) (interface{}, error) {
return check, nil
@ -29,10 +32,10 @@ func init() {
})))
// in room
router.GET("/api/rooms/:rid/items/:iid/checks/", apiHandler(itemInRoomHandler(func (item ckh.Item, _ ckh.Room, _ []byte) (interface{}, error) {
router.GET("/api/rooms/:rid/items/:iid/checks", apiHandler(itemInRoomHandler(func (item ckh.Item, _ ckh.Room, _ []byte) (interface{}, error) {
return item.GetChecks()
})))
router.POST("/api/rooms/:rid/items/:iid/checks/", apiHandler(itemInRoomHandler(newCheckInRoom)))
router.POST("/api/rooms/:rid/items/:iid/checks", apiHandler(itemInRoomHandler(newCheckInRoom)))
router.GET("/api/rooms/:rid/items/:iid/checks/:cid", apiHandler(checkInRoomHandler(func (check ckh.Check, _ ckh.Item, _ []byte) (interface{}, error) {
return check, nil

View File

@ -11,30 +11,64 @@ import (
)
func init() {
router.GET("/api/items/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.GET("/api/items", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.GetItems()
}))
router.DELETE("/api/items/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.DELETE("/api/items", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.ClearItems()
}))
router.GET("/api/rooms/:rid/items/", apiHandler(roomHandler(func (room ckh.Room, _ []byte) (interface{}, error) {
return room.GetItems()
router.GET("/api/rooms/:rid/items", apiHandler(roomHandler(func (room ckh.Room, _ []byte) (interface{}, error) {
if items, err := room.GetItems(); err != nil {
return nil, err
} else {
var res []item
for _, item := range items {
if i, err := displayItem(item); err != nil {
return nil, err
} else {
res = append(res, i)
}
}
return res, nil
}
})))
router.POST("/api/rooms/:rid/items/", apiHandler(roomHandler(newItem)))
router.DELETE("/api/rooms/:rid/items/", apiHandler(roomHandler(func (room ckh.Room, _ []byte) (interface{}, error) {
router.POST("/api/rooms/:rid/items", apiHandler(roomHandler(newItem)))
router.DELETE("/api/rooms/:rid/items", apiHandler(roomHandler(func (room ckh.Room, _ []byte) (interface{}, error) {
return room.ClearItems()
})))
router.GET("/api/rooms/:rid/items/:iid/", apiHandler(itemInRoomHandler(func (item ckh.Item, _ ckh.Room, _ []byte) (interface{}, error) {
return item, nil
router.GET("/api/rooms/:rid/items/:iid", apiHandler(itemInRoomHandler(func (item ckh.Item, _ ckh.Room, _ []byte) (interface{}, error) {
return displayItem(item)
})))
router.PUT("/api/rooms/:rid/items/:iid/", apiHandler(itemInRoomHandler(updateItem)))
router.DELETE("/api/rooms/:rid/items/:iid/", apiHandler(itemInRoomHandler(func (item ckh.Item, _ ckh.Room, _ []byte) (interface{}, error) {
router.PUT("/api/rooms/:rid/items/:iid", apiHandler(itemInRoomHandler(updateItem)))
router.DELETE("/api/rooms/:rid/items/:iid", apiHandler(itemInRoomHandler(func (item ckh.Item, _ ckh.Room, _ []byte) (interface{}, error) {
return item.Delete()
})))
}
type item struct {
Id int64 `json:"id"`
Label string `json:"label"`
Description string `json:"description"`
Tags []string `json:"tags"`
}
func displayItem(item ckh.Item) (i item, err error) {
var tags []ckh.Tag
if tags, err = item.GetTags(); err != nil {
return
} else {
for _, t := range tags {
i.Tags = append(i.Tags, t.Label)
}
}
i.Id = item.Id
i.Label = item.Label
i.Description = item.Description
return
}
func itemHandler(f func(ckh.Item, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) {
if iid, err := strconv.ParseInt(string(ps.ByName("iid")), 10, 64); err != nil {

View File

@ -11,11 +11,11 @@ import (
)
func init() {
router.GET("/api/rooms/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.GET("/api/rooms", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.GetRooms()
}))
router.POST("/api/rooms/", apiHandler(newRoom))
router.DELETE("/api/rooms/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.POST("/api/rooms", apiHandler(newRoom))
router.DELETE("/api/rooms", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.ClearRooms()
}))

View File

@ -11,11 +11,11 @@ import (
)
func init() {
router.GET("/api/tags/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.GET("/api/tags", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.GetTags()
}))
router.POST("/api/tags/", apiHandler(newTag))
router.DELETE("/api/tags/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.POST("/api/tags", apiHandler(newTag))
router.DELETE("/api/tags", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.ClearTags()
}))
@ -35,6 +35,9 @@ func init() {
router.GET("/api/items/:iid/tags", apiHandler(itemHandler(func (item ckh.Item, _ []byte) (interface{}, error) {
return item.GetTags()
})))
router.DELETE("/api/items/:iid/tags", apiHandler(itemHandler(func (item ckh.Item, _ []byte) (interface{}, error) {
return item.ClearItemTags()
})))
router.PUT("/api/items/:iid/tags/:tid", apiHandler(itemTagHandler(func (item ckh.Item, tag ckh.Tag, _ []byte) (interface{}, error) {
_, err := tag.AddItem(item)
return tag, err

View File

@ -11,11 +11,11 @@ import (
)
func init() {
router.GET("/api/users/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.GET("/api/users", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.GetUsers()
}))
router.POST("/api/users/", apiHandler(newUser))
router.DELETE("/api/users/", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
router.POST("/api/users", apiHandler(newUser))
router.DELETE("/api/users", apiHandler(func (_ httprouter.Params, _ []byte) (interface{}, error) {
return ckh.ClearUsers()
}))

View File

@ -2,18 +2,36 @@
<html ng-app="CheckHomeApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Terrasses de la Bièvre - remise des clefs</title>
<link href="/css/bootstrap.min.css" type="text/css" rel="stylesheet">
<link href="/css/glyphicon.css" type="text/css" rel="stylesheet" media="screen">
<base href="/">
</head>
<body>
<nav class="nav">
<a class="nav-link" href="/">Accueil</a>
<a class="nav-link" href="/items">Éléments</a>
<a class="nav-link" href="/rooms">Pièces</a>
<a class="nav-link" href="/tags">Étiquettes</a>
<a class="nav-link" href="/users">Utilisateurs</a>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-2">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item" ng-class="{'active': currecurrentPage == '' || currentPage == 'home'}">
<a class="nav-link" href="/"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> Accueil</a>
</li>
<li class="nav-item" ng-class="{'active': currentPage == 'items'}">
<a class="nav-link" href="/items"><span class="glyphicon glyphicon-th-list" aria-hidden="true"></span> Éléments</a>
</li>
<li class="nav-item" ng-class="{'active': currentPage == 'rooms'}">
<a class="nav-link" href="/rooms"><span class="glyphicon glyphicon-tower" aria-hidden="true"></span> Pièces</a>
</li>
<li class="nav-item" ng-class="{'active': currentPage == 'tags'}">
<a class="nav-link" href="/tags"><span class="glyphicon glyphicon-tags" aria-hidden="true"></span> Étiquettes</a>
</li>
<li class="nav-item" ng-class="{'active': currentPage == 'users'}">
<a class="nav-link" href="/users"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Utilisateurs</a>
</li>
</div>
</nav>
<div class="container" ng-view></div>
@ -24,6 +42,7 @@
<script src="/js/angular.min.js"></script>
<script src="/js/angular-resource.min.js"></script>
<script src="/js/angular-route.min.js"></script>
<script src="/js/angular-sanitize.min.js"></script>
<script src="/js/ckhome.js"></script>
</body>
</html>

View File

@ -1,4 +1,4 @@
angular.module("CheckHomeApp", ["ngRoute", "ngResource"])
angular.module("CheckHomeApp", ["ngRoute", "ngResource", "ngSanitize"])
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when("/items", {
@ -60,18 +60,51 @@ angular.module("CheckHomeApp")
})
});
function newCheck(ItemChecks, iid, passed, cb) {
var c = new ItemChecks();
c.passed = passed;
c.comment = $("#comment").val();
c.$save({itemId: iid}, function(res) {
$("#comment").val("");
$('#commentModal').modal("hide");
cb(res);
});
}
angular.module("CheckHomeApp")
.controller("VersionController", function($scope, Version) {
$scope.v = Version.get();
})
.controller("RoomsController", function($scope, Room) {
.controller("RoomsController", function(ItemChecks, Room, $scope, $rootScope) {
$scope.rooms = Room.query();
$rootScope.tagsX = [];
$rootScope.tagsReverse = false;
$rootScope.tagsShown = {};
$rootScope.stateShown = { "yes": true, "yesbut": true, "nobut": true, "no": true, "next": false , "na": true };
$scope.newRoom = function() {
var t = new Room();
t.edit = true;
$scope.rooms.push(t);
}
$scope.toggleRoom = function() {
this.room.closed = !this.room.closed;
}
$scope.showOnlyThisRoom = function() {
$scope.rooms.forEach(function(r) {
r.closed = true;
});
this.room.closed = false;
}
$scope.toggleStateS = function(state) {
$rootScope.stateShown[state] = !$rootScope.stateShown[state];
}
$scope.toggleAllStates = function() {
Object.keys($rootScope.stateShown).forEach(function(v) {
$rootScope.stateShown[v] = $rootScope.statesSelect;
})
$rootScope.statesSelect = !$rootScope.statesSelect;
}
$scope.editRoom = function() {
this.room.edit = true;
}
@ -86,15 +119,63 @@ angular.module("CheckHomeApp")
$scope.room.splice(rk, 1);
});
}
$scope.skipCheck = function() {
$rootScope.selectedItem.action = "next";
$scope.submitModal();
}
$scope.submitModal = function() {
newCheck(ItemChecks, $rootScope.selectedItem.id, $rootScope.selectedItem.action, $rootScope.selectedItem.cb)
}
})
.controller("ItemsRoomController", function($scope, ItemRoom) {
.controller("ItemsRoomController", function($scope, $rootScope, ItemRoom) {
$scope.items = ItemRoom.query({roomId: $scope.room.id});
$scope.items.$promise.then(function(){
$scope.items.forEach(function(item) {
if (item.tags != null)
item.tags.forEach(function(v) {
if ($rootScope.tagsX.indexOf(v) == -1) {
$rootScope.tagsX.push(v);
$rootScope.tagsShown[v] = true;
}
})
})
});
$scope.filterByTag = function() {
if (this.item.tags == null)
return true;
if (!$rootScope.tagsReverse) {
var display = false;
this.item.tags.forEach(function(v) {
$rootScope.tagsX.forEach(function(t) {
if (display || ($rootScope.tagsShown[t] && t == v))
display = true;
});
});
return display;
} else {
var display = true;
this.item.tags.forEach(function(v) {
$rootScope.tagsX.forEach(function(t) {
if (!display || ($rootScope.tagsShown[t] && t == v))
display = false;
});
});
return display;
}
}
$scope.newItem = function() {
var t = new ItemRoom();
t.edit = true;
$scope.items.push(t);
}
$scope.toggleDescription = function() {
this.item.open = !this.item.open;
}
$scope.editItem = function() {
this.item.edit = true;
}
@ -105,19 +186,16 @@ angular.module("CheckHomeApp")
this.item.$update({roomId: this.room.id});
}
$scope.delItem = function(ik) {
this.item.$delete().then(function() {
this.item.$delete({roomId: this.room.id}).then(function() {
$scope.items.splice(ik, 1);
});
}
})
.controller("ChecksItemController", function($scope, ItemChecks) {
.controller("ChecksItemController", function($scope, ItemChecks, $rootScope) {
$rootScope.selectedItem = {};
$scope.ncomment = "";
$scope.checks = ItemChecks.query({itemId: $scope.item.id});
$scope.registerComment = function() {
$scope.newCheck($("#assocRes").val());
}
$scope.min_checks = function() {
function state2int(state) {
switch(state) {
@ -129,8 +207,10 @@ angular.module("CheckHomeApp")
return 2;
case "no":
return 1;
default:
case "next":
return 5;
default:
return 6;
}
}
var min = "N/A";
@ -140,28 +220,43 @@ angular.module("CheckHomeApp")
});
return min;
}
$scope.newCheck = function(passed) {
var c = new ItemChecks();
c.passed = passed;
c.comment = $("#comment").val();
c.$save({itemId: $scope.item.id}, function(res) {
$("#comment").val("");
$scope.checks.push(res)
$scope.filterByCheck = function() {
if ((this.checks == null || this.checks.length == 0) && $rootScope.stateShown["na"])
return true;
var display = false;
this.checks.forEach(function(v) {
Object.keys($rootScope.stateShown).forEach(function(k) {
if(display || (k == v["passed"] && $rootScope.stateShown[k]))
display = true;
});
});
return display;
}
$scope.checkOk = function() {
$scope.newCheck("yes");
}
$scope.checkMok = function() {
$("#assocRes").val("yesbut");
$scope.checkCommon = function(modal, res) {
if (modal) {
var cb = function(res) { $scope.checks.push(res); }
$rootScope.selectedItem = this.item;
$rootScope.selectedItem.action = res;
$rootScope.selectedItem.cb = cb;
$('#commentModal').modal("show");
document.getElementById("comment").focus();
} else {
newCheck(ItemChecks, $scope.item.id, res, function(res) { $scope.checks.push(res); });
}
$scope.checkMko = function() {
$("#assocRes").val("nobut");
$('#commentModal').modal("show");
}
$scope.checkKo = function() {
$scope.newCheck("no");
$scope.checkOk = function(modal) {
$scope.checkCommon(modal, "yes");
}
$scope.checkMok = function(modal) {
$scope.checkCommon(modal, "yesbut");
}
$scope.checkMko = function(modal) {
$scope.checkCommon(modal, "nobut");
}
$scope.checkKo = function(modal) {
$scope.checkCommon(modal, "no");
}
$scope.delCheck = function(ck) {
@ -170,9 +265,24 @@ angular.module("CheckHomeApp")
});
}
})
.controller("TagsController", function($scope, Tag) {
.controller("TagsController", function($scope, $rootScope, Tag) {
$scope.tags = Tag.query();
$rootScope.tagsSelect = false;
$scope.toggleAllTags = function() {
$rootScope.tagsX.forEach(function(v) {
$rootScope.tagsShown[v] = $rootScope.tagsSelect;
})
$rootScope.tagsSelect = !$rootScope.tagsSelect;
}
$scope.toggleReverseTags = function(tag) {
$rootScope.tagsReverse = !$rootScope.tagsReverse;
}
$scope.toggleTagS = function(tag) {
$rootScope.tagsShown[tag] = !$rootScope.tagsShown[tag];
$rootScope.tagsSelect = false;
}
$scope.newTag = function() {
var t = new Tag();
t.edit = true;
@ -193,7 +303,7 @@ angular.module("CheckHomeApp")
});
}
})
.controller("TagsItemController", function($scope, TagsItem) {
.controller("TagsItemController", function($scope, TagsItem, $http) {
$scope.itags = TagsItem.query({itemId: $scope.item.id});
$scope.newItemTag = function() {
@ -202,16 +312,19 @@ angular.module("CheckHomeApp")
$scope.itags.push(t);
}
$scope.editItemTag = function() {
this.tag.val = this.tag.id;
this.tag.edit = true;
}
$scope.editItemTagPass = function() {
this.tag.editpass = true;
}
$scope.saveItemTag = function() {
if (this.tag.id === undefined)
this.tag.$save({itemId: $scope.item.id, tagId: this.tag.val})
else
this.tag.$update();
else {
var v = this.tag;
var val = this.tag.val;
v.$delete({itemId: $scope.item.id, tagId: v.id}).then(function() {
v.$save({itemId: $scope.item.id, tagId: val});
});
}
}
$scope.delItemTag = function(tk) {
this.tag.$delete({itemId: $scope.item.id, tagId: this.tag.id}).then(function() {
@ -219,7 +332,7 @@ angular.module("CheckHomeApp")
});
}
})
.controller("UsersController", function($scope, User) {
.controller("UsersController", function($scope, User, $http, $location) {
$scope.users = User.query();
$scope.newUser = function() {
@ -245,4 +358,10 @@ angular.module("CheckHomeApp")
$scope.users.splice(uk, 1);
});
}
$scope.razchecks = function() {
if (confirm("Sûr d'effacer tous les tests effectués ?"))
$http.delete("/api/checks").then(function() {
$location.url("/");
});
}
});

View File

@ -1,66 +1,94 @@
<div class="row">
<div class="col-md btn-group btn-group-toggle" data-toggle="buttons" ng-controller="TagsController" style="overflow: auto; width: inherit">
<button type="button" class="btn" ng-class="{'btn-secondary': !tagsSelect, 'btn-primary': tagsSelect}" ng-click="toggleAllTags()">All</button>
<button type="button" class="btn" ng-class="{'btn-secondary': !tagsReverse, 'btn-primary': tagsReverse}" ng-click="toggleReverseTags()"><span class="glyphicon" ng-class="{'glyphicon-resize-full': tagsReverse, 'glyphicon-resize-small': !tagsReverse}" aria-hidden="true"></span></button>
<button type="button" class="btn" ng-class="{'btn-secondary': !tagsShown[tag], 'btn-primary': tagsShown[tag]}" ng-click="toggleTagS(tag)" ng-repeat="tag in tagsX">{{tag}}</button>
</div>
<div class="col-md-auto btn-group btn-group-toggle" data-toggle="buttons" style="overflow: auto; width: inherit">
<button type="button" class="btn" ng-class="{'btn-secondary': !statesSelect, 'btn-primary': statesSelect}" ng-click="toggleAllStates()">All</button>
<button type="button" class="btn" ng-class="{'btn-secondary': !stateShown['na'], 'btn-light': stateShown['na']}" ng-click="toggleStateS('na')"><span class="glyphicon glyphicon-inbox" aria-hidden="true"></span></button>
<button type="button" class="btn" ng-class="{'btn-secondary': !stateShown['yes'], 'btn-success': stateShown['yes']}" ng-click="toggleStateS('yes')">OK</button>
<button type="button" class="btn" ng-class="{'btn-secondary': !stateShown['yesbut'], 'btn-info': stateShown['yesbut']}" ng-click="toggleStateS('yesbut')">OK</button>
<button type="button" class="btn" ng-class="{'btn-secondary': !stateShown['nobut'], 'btn-warning': stateShown['nobut']}" ng-click="toggleStateS('nobut')">KO</button>
<button type="button" class="btn" ng-class="{'btn-secondary': !stateShown['no'], 'btn-danger': stateShown['no']}" ng-click="toggleStateS('no')">KO</button>
<button type="button" class="btn" ng-class="{'btn-secondary': !stateShown['next'], 'btn-dark': stateShown['next']}" ng-click="toggleStateS('next')"><span class="glyphicon glyphicon-calendar" aria-hidden="true"></span></button>
</div>
</div>
<div ng-repeat="room in rooms" ng-controller="ItemsRoomController">
<h2>
<h2 ng-click="toggleRoom()" ng-dblclick="showOnlyThisRoom()" id="room-{{room.id}}">
{{room.label}}
<small class="text-muted" ng-show="room.closed">(<ng-pluralize count="items.length" when="{'0': 'aucun élément', 'one': '{} élément masqué', other: '{} éléments masqués'}"></ng-pluralize>)</small>
</h2>
<div class="card" ng-repeat="item in items" ng-controller="ChecksItemController">
<div class="card-header" ng-class="{'bg-success': min_checks() == 'yes', 'bg-info': min_checks() == 'yesbut', 'bg-warning': min_checks() == 'nobut', 'bg-danger': min_checks() == 'no', 'bg-secondary': min_checks() == 'N/A'}" ng-controller="TagsItemController">
<div ng-repeat="item in items" ng-controller="ChecksItemController">
<div class="card" ng-if="!room.closed && filterByTag() && filterByCheck()">
<div class="card-header" ng-class="{'bg-success': min_checks() == 'yes', 'bg-info': min_checks() == 'yesbut', 'bg-warning': min_checks() == 'nobut', 'bg-danger': min_checks() == 'no', 'bg-secondary': min_checks() == 'N/A'}" ng-controller="TagsItemController" ng-click="toggleDescription()">
<div class="row">
<div class="col-md">
<div class="col-sm-auto">
<span ng-if="min_checks() == 'yes'" class="badge badge-success"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></span>
<span ng-if="min_checks() == 'yesbut'" class="badge badge-info"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></span>
<span ng-if="min_checks() == 'nobut'" class="badge badge-warning"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></span>
<span ng-if="min_checks() == 'no'" class="badge badge-danger"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></span>
<span ng-if="min_checks() == 'next'" class="badge badge-dark"><span class="glyphicon glyphicon-calendar" aria-hidden="true"></span></span>
<span ng-if="min_checks() != 'next' && min_checks() != 'no' && min_checks() != 'nobut' && min_checks() != 'yes' && min_checks() != 'yesbut'" class="badge badge-secondary"><span class="glyphicon glyphicon-chevron-right" aria-hidden="true" ng-if="!item.open"></span><span class="glyphicon glyphicon-chevron-down" aria-hidden="true" ng-if="item.open"></span></span>
<strong>{{item.label}}</strong>
</div>
<div class="col-md text-right">
<button type="button" class="btn btn-outline-success" ng-click="checkOk()">OK</button>
<button type="button" class="btn btn-outline-info" ng-click="checkMok()">OK, mais&hellip;</button>
<button type="button" class="btn btn-outline-warning" ng-click="checkMko()">KO, mais&hellip;</button>
<button type="button" class="btn btn-outline-danger" ng-click="checkKo()">KO</button>
<div class="col-sm text-right">
<button type="button" class="btn btn-sm btn-success" ng-click="checkOk(false)" ng-dblclick="checkOk(true)">OK</button>
<button type="button" class="btn btn-sm btn-info" ng-click="checkMok(true)">OK mais&hellip;</button>
<button type="button" class="btn btn-sm btn-warning" ng-click="checkMko(true)">KO mais&hellip;</button>
<button type="button" class="btn btn-sm btn-danger" ng-click="checkKo(true)">KO</button>
</div>
</div>
</div>
<div class="card-body">
<div class="card-body" ng-if="item.description || item.tags" ng-show="item.open">
<p class="card-text" ng-if="item.description" ng-bind="item.description"></p>
<p class="card-text" ng-if="item.tags">
<span class="badge" ng-class="{'badge-secondary': !tagsShown[tag], 'badge-primary': tagsShown[tag]}" ng-repeat="tag in item.tags">{{tag}}</span>
</p>
</div>
<ul class="list-group list-group-flush">
<ul class="list-group list-group-flush" ng-if="item.open">
<li class="list-group-item" ng-repeat="(ck, check) in checks">
<span ng-if="check.passed == 'yes'" class="badge badge-success">OK</span>
<span ng-if="check.passed == 'yesbut'" class="badge badge-info">OK</span>
<span ng-if="check.passed == 'nobut'" class="badge badge-warning">KO</span>
<span ng-if="check.passed == 'no'" class="badge badge-danger">KO</span>
<span ng-if="check.passed == 'next'" class="badge badge-dark"><span class="glyphicon glyphicon-calendar" aria-hidden="true"></span></span>
<a ng-click="delCheck(ck)" class="float-right" ng-if="!check.id_user">
<span class="glyphicon glyphicon-minus" aria-hidden="true"></span>
</a>
{{check.date | date : 'medium'}}<span ng-show="check.comment">&nbsp;:</span>
{{check.comment}}
</li>
</ul>
</div>
</div>
</div>
<div class="modal fade" id="commentModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form ng-submit="submitModal()">
<div class="modal-header">
<h5 class="modal-title" id="commentModalLabel">Nouveau commentaire</h5>
<h5 class="modal-title" id="commentModalLabel">{{selectedItem.label}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form>
<p ng-if="selectedItem.comment" ng-bind="selectedItem"></p>
<div class="form-group">
<label for="comment">Commentaire</label>
<input type="text" class="form-control" id="comment" placeholder="Commentaire...">
<input type="hidden" id="assocRes">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
<button type="button" class="btn btn-primary" ng-click="registerComment()">Inscrire le commentaire</button>
<button type="submit" class="btn btn-primary" ng-class="{'btn-success': selectedItem.action == 'yes', 'btn-info': selectedItem.action == 'yesbut', 'btn-warning': selectedItem.action == 'nobut', 'btn-danger': selectedItem.action == 'no', 'btn-dark': selectedItem.action == 'next'}">Continuer &hellip;</button>
<button type="button" class="btn btn-dark" ng-show="selectedItem.action == 'no'" ng-click="skipCheck()">Tester plus tard</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -4,10 +4,10 @@
<ul ng-controller="ItemsRoomController">
<li ng-repeat="(ik, item) in items">
<span ng-if="!item.edit" ng-controller="TagsItemController">
<strong>{{ item.label }}</strong>
<strong ng-dblclick="editItem()">{{ item.label }}</strong>
<span class="badge badge-secondary" ng-repeat="(tk, tag) in itags">
<span ng-if="!tag.edit">{{ tag.label }}</span>
<select ng-options="tag.id as tag.label for tag in tags track by tag.id" ng-model="tag.val" ng-if="tag.edit">
<span ng-if="!tag.edit" ng-dblclick="editItemTag()">{{ tag.label }}</span>
<select ng-options="tag.id as tag.label for tag in tags track by tag.id" ng-change="saveItemTag()" ng-model="tag.val" ng-if="tag.edit">
</select>
<a ng-click="delItemTag(tk)" ng-if="!tag.edit">
<span class="glyphicon glyphicon-minus" aria-hidden="true"></span>
@ -26,7 +26,7 @@
<button type="button" class="btn btn-sm btn-danger" ng-click="delItem(ik)" ng-if="!item.edit">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button><br>
{{ item.description }}
<p ng-bind-html="item.description"></p>
</span>
<form ng-if="item.edit" ng-submit="saveItem()">
<input ng-model="item.label">

View File

@ -24,3 +24,9 @@
</button>
</li>
</ul>
<hr>
<button type="button" class="btn btn-sm btn-dark" ng-click="razchecks()">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> RAZ test passés
</button>

View File

@ -1,17 +1,20 @@
package ckh
import ()
import (
"time"
)
type Check struct {
Id int64 `json:"id"`
IdItem int64 `json:"id_item"`
IdUser int64 `json:"id_user"`
Date time.Time `json:"date"`
Passed string `json:"passed"`
Comment string `json:"comment",omitempty`
}
func GetChecks() (checks []Check, err error) {
if rows, errr := DBQuery("SELECT id_check, id_item, id_user, passed, comment FROM checks"); errr != nil {
if rows, errr := DBQuery("SELECT id_check, id_item, id_user, date, passed, comment FROM checks"); errr != nil {
return nil, errr
} else {
defer rows.Close()
@ -19,7 +22,7 @@ func GetChecks() (checks []Check, err error) {
checks = make([]Check, 0)
for rows.Next() {
var c Check
if err = rows.Scan(&c.Id, &c.IdItem, &c.IdUser, &c.Passed, &c.Comment); err != nil {
if err = rows.Scan(&c.Id, &c.IdItem, &c.IdUser, &c.Date, &c.Passed, &c.Comment); err != nil {
return
}
checks = append(checks, c)
@ -33,7 +36,7 @@ func GetChecks() (checks []Check, err error) {
}
func (i Item) GetChecks() (checks []Check, err error) {
if rows, errr := DBQuery("SELECT id_check, id_item, id_user, passed, comment FROM checks WHERE id_item = ?", i.Id); errr != nil {
if rows, errr := DBQuery("SELECT id_check, id_item, id_user, date, passed, comment FROM checks WHERE id_item = ?", i.Id); errr != nil {
return nil, errr
} else {
defer rows.Close()
@ -41,7 +44,7 @@ func (i Item) GetChecks() (checks []Check, err error) {
checks = make([]Check, 0)
for rows.Next() {
var c Check
if err = rows.Scan(&c.Id, &c.IdItem, &c.IdUser, &c.Passed, &c.Comment); err != nil {
if err = rows.Scan(&c.Id, &c.IdItem, &c.IdUser, &c.Date, &c.Passed, &c.Comment); err != nil {
return
}
checks = append(checks, c)
@ -55,27 +58,27 @@ func (i Item) GetChecks() (checks []Check, err error) {
}
func GetCheck(id int64) (c Check, err error) {
err = DBQueryRow("SELECT id_check, id_item, id_user, passed, comment FROM checks WHERE id_check = ?", id).Scan(&c.Id, &c.IdItem, &c.IdUser, &c.Passed, &c.Comment)
err = DBQueryRow("SELECT id_check, id_item, id_user, date, passed, comment FROM checks WHERE id_check = ?", id).Scan(&c.Id, &c.IdItem, &c.IdUser, &c.Date, &c.Passed, &c.Comment)
return
}
func (i Item) GetCheck(id int64) (c Check, err error) {
err = DBQueryRow("SELECT id_check, id_item, id_user, passed, comment FROM checks WHERE id_check = ? AND id_item = ?", id, i.Id).Scan(&c.Id, &c.IdItem, &c.IdUser, &c.Passed, &c.Comment)
err = DBQueryRow("SELECT id_check, id_item, id_user, date, passed, comment FROM checks WHERE id_check = ? AND id_item = ?", id, i.Id).Scan(&c.Id, &c.IdItem, &c.IdUser, &c.Date, &c.Passed, &c.Comment)
return
}
func (i Item) NewCheck(user User, state string, comment string) (Check, error) {
if res, err := DBExec("INSERT INTO checks (id_item, id_user, passed, comment) VALUES (?, ?, ?, ?)", i.Id, user.Id, state, comment); err != nil {
if res, err := DBExec("INSERT INTO checks (id_item, id_user, date, passed, comment) VALUES (?, ?, ?, ?, ?)", i.Id, user.Id, time.Now(), state, comment); err != nil {
return Check{}, err
} else if cid, err := res.LastInsertId(); err != nil {
return Check{}, err
} else {
return Check{cid, i.Id, user.Id, state, comment}, nil
return Check{cid, i.Id, user.Id, time.Now(), state, comment}, nil
}
}
func (c Check) Update() (int64, error) {
if res, err := DBExec("UPDATE checks SET id_item = ?, id_user = ?, passed = ?, comment = ? WHERE id_check = ?", c.IdItem, c.IdUser, c.Passed, c.Comment, c.Id); err != nil {
if res, err := DBExec("UPDATE checks SET id_item = ?, id_user = ?, date = ?, passed = ?, comment = ? WHERE id_check = ?", c.IdItem, c.IdUser, c.Date, c.Passed, c.Comment, c.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err

View File

@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS tags (id_tag INTEGER NOT NULL PRIMARY KEY AUTO_INCREM
CREATE TABLE IF NOT EXISTS items (id_item INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, label TEXT NOT NULL, description TEXT NOT NULL, id_room INTEGER);
CREATE TABLE IF NOT EXISTS item_tag (id_item INTEGER NOT NULL, id_tag INTEGER NOT NULL);
CREATE TABLE IF NOT EXISTS users (id_user INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, username VARCHAR(255), password BINARY(64));
CREATE TABLE IF NOT EXISTS checks (id_check INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_item INTEGER NOT NULL, id_user INTEGER NOT NULL, passed ENUM('yes', 'no', 'yesbut', 'nobut') NOT NULL, comment TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS checks (id_check INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_item INTEGER NOT NULL, id_user INTEGER NOT NULL, date DATETIME DEFAULT CURRENT_TIMESTAMP, passed ENUM('yes', 'no', 'yesbut', 'nobut', 'next') NOT NULL, comment TEXT NOT NULL);
`
for _, ln := range strings.Split(ct, "\n") {
if len(ln) == 0 {