forked from DGNum/gestioCOF
Interface K-Psul
- Création style kpsul.css - Affichage trigramme et données du compte. Couleurs en fonction de l'état du compte (négatif, pas beaucoup, gelé, ok) - Affichage de la sélection et des données de la caisse - Ajout des boutons pour les charges et retraits (juste les boutons) - Ajout du champ d'autocomplétion pour les articles (et ça autocomplète bien) - Correction css général - K-Psul JS: utilisation de $.extend pour les données récupérées en ajax/websocket pour utiliser les valeurs par défaut (plus joli)
This commit is contained in:
parent
39af9afd5b
commit
82f0dd9638
6 changed files with 414 additions and 60 deletions
|
@ -136,7 +136,11 @@ class KPsulAccountForm(forms.ModelForm):
|
|||
model = Account
|
||||
fields = ['trigramme']
|
||||
widgets = {
|
||||
'trigramme': forms.TextInput(attrs={'autocomplete': 'off'}),
|
||||
'trigramme': forms.TextInput(
|
||||
attrs={
|
||||
'autocomplete': 'off',
|
||||
'spellcheck': 'false',
|
||||
}),
|
||||
}
|
||||
|
||||
class KPsulCheckoutForm(forms.Form):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@import url("nav.css");
|
||||
@import url("kpsul.css");
|
||||
|
||||
body {
|
||||
margin-top:50px;
|
||||
|
@ -13,8 +14,8 @@ a:focus, a:hover {
|
|||
color:#C8102E;
|
||||
}
|
||||
|
||||
.btn-group .btn+.btn, .btn-group .btn+.btn-group, .btn-group .btn-group+.btn, .btn-group .btn-group+.btn-group {
|
||||
margin-left:5px;
|
||||
:focus {
|
||||
outline:none;
|
||||
}
|
||||
|
||||
.btn, .btn-lg, .btn-group-lg>.btn {
|
||||
|
@ -33,12 +34,9 @@ a:focus, a:hover {
|
|||
color:#FFF;
|
||||
}
|
||||
|
||||
.container-fluid .row:first-child {
|
||||
.row-page-header {
|
||||
background-color:rgba(200,16,46,1);
|
||||
color:#FFF;
|
||||
}
|
||||
|
||||
.row.row-page-header {
|
||||
border-bottom:3px solid #000;
|
||||
}
|
||||
|
||||
|
|
236
kfet/static/kfet/css/kpsul.css
Normal file
236
kfet/static/kfet/css/kpsul.css
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Top row
|
||||
*/
|
||||
|
||||
.row.kpsul_top {
|
||||
padding:0 15px;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.row.kpsul_top > div {
|
||||
margin-top:15px;
|
||||
}
|
||||
|
||||
/* Account */
|
||||
|
||||
#account {
|
||||
border:1px solid #ddd;
|
||||
color:black;
|
||||
height:160px;
|
||||
}
|
||||
|
||||
#account[data-balance="ok"] { border-color:#009011; }
|
||||
#account[data-balance="ok"] #account_form input { background:#009011; color:#FFF;}
|
||||
#account[data-balance="low"] { border-color:#EC6400; }
|
||||
#account[data-balance="low"] #account_form input { background:#EC6400; color:#FFF; }
|
||||
#account[data-balance="neg"] { border-color:#C8102E; }
|
||||
#account[data-balance="neg"] #account_form input { background:#C8102E; color:#FFF; }
|
||||
#account[data-balance="frozen"] { border-color:#000FBA; }
|
||||
#account[data-balance="frozen"] #account_form input { background:#000FBA; color:#FFF; }
|
||||
|
||||
#account_form {
|
||||
padding:0;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#account_form input {
|
||||
width:100%;
|
||||
height:100%;
|
||||
|
||||
padding:0;
|
||||
padding-bottom:10px;
|
||||
|
||||
border:0;
|
||||
border-radius:0;
|
||||
|
||||
background:#ddd;
|
||||
|
||||
font-family:'Roboto Mono';
|
||||
font-size:70px;
|
||||
font-weight:bold;
|
||||
|
||||
text-align:center;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#account {
|
||||
margin-right:0;
|
||||
}
|
||||
|
||||
#account_form input {
|
||||
font-size:85px;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
#account_form input {
|
||||
font-size:100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#account_data {
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#account_data .data_line {
|
||||
line-height:24px;
|
||||
|
||||
font-family:'Roboto Mono';
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
#account_data #account-balance{
|
||||
height:60px;
|
||||
line-height:60px;
|
||||
|
||||
font-size:60px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
#account_data #account-name {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
/* Checkout */
|
||||
|
||||
#checkout {
|
||||
border:1px solid #ddd;
|
||||
padding:0;
|
||||
height:160px;
|
||||
font-family:'Roboto Mono';
|
||||
}
|
||||
|
||||
#checkout_form select {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
cursor:pointer;
|
||||
outline:none;
|
||||
border:0;
|
||||
|
||||
width:100%;
|
||||
height:50px;
|
||||
padding:0 15px;
|
||||
|
||||
background:#ddd;
|
||||
|
||||
font-weight:bold;
|
||||
font-size:18px;
|
||||
}
|
||||
|
||||
#checkout_form select option {
|
||||
height:25px;
|
||||
padding:0 15px;
|
||||
line-height:25px;
|
||||
font-weight:normal;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
#checkout_data {
|
||||
padding:0 15px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Second part
|
||||
*/
|
||||
|
||||
.row.kpsul_middle {
|
||||
padding:0 15px;
|
||||
font-family:'Roboto Mono';
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.row.kpsul_middle > div {
|
||||
margin-top:15px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.row.kpsul_middle > div:first-child > div {
|
||||
margin-right:0;
|
||||
}
|
||||
|
||||
@media (min-width:768px) {
|
||||
.row.kpsul_middle > div:first-child > div {
|
||||
margin-right:15px
|
||||
}
|
||||
}
|
||||
|
||||
/* Special operations */
|
||||
|
||||
#special_operations {
|
||||
height:40px;
|
||||
}
|
||||
|
||||
#special_operations button {
|
||||
height:100%;
|
||||
width:50%;
|
||||
|
||||
float:left;
|
||||
|
||||
background:#ddd;
|
||||
color:#000;
|
||||
|
||||
font-size:18px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
#special_operations button:focus {
|
||||
outline:none;
|
||||
}
|
||||
|
||||
#operation_deposit:focus, #operation_deposit:hover {
|
||||
background:#009011;
|
||||
color:#FFF;
|
||||
}
|
||||
|
||||
#operation_withdraw:focus, #operation_withdraw:hover {
|
||||
background:#C8102E;
|
||||
color:#FFF;
|
||||
}
|
||||
|
||||
/* Article autocomplete */
|
||||
|
||||
#article_selection {
|
||||
height:40px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
#article_selection input {
|
||||
height:100%;
|
||||
float:left;
|
||||
border:1px solid #ddd;
|
||||
border-radius:0;
|
||||
border-top:0;
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
#article_selection input+input {
|
||||
border-left:0;
|
||||
}
|
||||
|
||||
#article_selection input[type=number] {
|
||||
-moz-appearance:textfield;
|
||||
}
|
||||
|
||||
#article_selection input[type=number]::-webkit-inner-spin-button,
|
||||
#article_selection input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
#article_autocomplete {
|
||||
width:95%;
|
||||
padding-left:10px;
|
||||
}
|
||||
|
||||
#article_number {
|
||||
width:5%;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
/* Article data */
|
||||
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
{# CSS #}
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto|Oswald:400,700' rel='stylesheet' type='text/css'>
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto|Oswald:400,700|Roboto+Mono:400,700' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'kfet/css/index.css' %}">
|
||||
|
||||
{# JS #}
|
||||
|
|
|
@ -16,48 +16,79 @@
|
|||
|
||||
<form id="operationgroup_form">{{ operationgroup_form }}</form>
|
||||
|
||||
{{ trigramme_form.as_p }}
|
||||
<div id="account_data">
|
||||
<p id="account-balance"></p>
|
||||
<p id="account-name"></p>
|
||||
<p id="account-email"></p>
|
||||
<p id="account-is_cof"></p>
|
||||
<p id="account-promo"></p>
|
||||
<p id="account-is_frozen"></p>
|
||||
<p id="account-departement"></p>
|
||||
<p id="account-nickname"></p>
|
||||
<div class="row kpsul_top">
|
||||
<div class="col-sm-8">
|
||||
<div class="row" id="account">
|
||||
<div class="col-lg-3 col-xs-4" id="account_form">
|
||||
{{ trigramme_form.trigramme }}
|
||||
</div>
|
||||
<div class="col-lg-9 col-xs-8" id="account_data">
|
||||
<div id="account-balance" class="data_line"></div>
|
||||
<div id="account-name" class="data_line"></div>
|
||||
<div id="account-nickname" class="data_line"></div>
|
||||
<div class="data_line">
|
||||
<span id="account-is_cof"></span>
|
||||
<span id="account-departement"></span>
|
||||
<span id="account-promo"></span>
|
||||
</div>
|
||||
<div id="account-email" class="data_line"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4" id="checkout">
|
||||
<div id="checkout_form">
|
||||
{{ checkout_form.checkout }}
|
||||
</div>
|
||||
<div id="checkout_data">
|
||||
<div>
|
||||
<b>En caisse:</b> <span id="checkout-balance"></span> €
|
||||
</div>
|
||||
<div>
|
||||
<b>Dernier relevé: </b><br>
|
||||
<span id="checkout-last_statement_balance"></span> €
|
||||
à <span id="checkout-last_statement_at"></span>
|
||||
par <span id="checkout-last_statement_by_trigramme"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ checkout_form.as_p }}
|
||||
<div id="checkout_data">
|
||||
<p id="checkout-name"></p>
|
||||
<p id="checkout-balance"></p>
|
||||
<p id="checkout-valid_from"></p>
|
||||
<p id="checkout-valid_to"></p>
|
||||
<p id="checkout-last_statement_balance"></p>
|
||||
<p id="checkout-last_statement_at"></p>
|
||||
<p id="checkout-last_statement_by_trigramme"></p>
|
||||
<p id="checkout-last_statement_by_first_name"></p>
|
||||
<p id="checkout-last_statement_by_last_name"></p>
|
||||
<div class="row kpsul_middle">
|
||||
<div class="col-sm-8">
|
||||
<div>
|
||||
<div id="special_operations">
|
||||
<button role="button" class="btn" id="operation_deposit">Charge</button>
|
||||
<button role="button" class="btn" id="operation_withdraw">Retrait</button>
|
||||
</div>
|
||||
<div id="article_selection">
|
||||
<input type="text" id="article_autocomplete">
|
||||
<input type="number" id="article_number" step="1" min="1">
|
||||
<input type="hidden" id="article_id" value="">
|
||||
</div>
|
||||
<div id="articles_data">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Nom</td>
|
||||
<td>Catégorie</td>
|
||||
<td>Prix</td>
|
||||
<td>Stock</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="operation_formset">
|
||||
{{ operation_formset.as_p }}
|
||||
</form>
|
||||
|
||||
<table id="articles_data">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Nom</td>
|
||||
<td>Catégorie</td>
|
||||
<td>Prix</td>
|
||||
<td>Stock</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<button type="button" id="perform_operations">Valider</button>
|
||||
|
||||
<form id="cancel_form">
|
||||
|
@ -106,6 +137,7 @@ $(document).ready(function() {
|
|||
'is_cof' : false,
|
||||
'promo' : '',
|
||||
'balance': '',
|
||||
'trigramme' : '',
|
||||
'is_frozen' : false,
|
||||
'departement': '',
|
||||
'nickname' : '',
|
||||
|
@ -113,10 +145,19 @@ $(document).ready(function() {
|
|||
|
||||
// Display data
|
||||
function displayAccountData() {
|
||||
for (var elem in account_data_default) {
|
||||
$('#account-'+elem).text(
|
||||
account_data[elem] ? account_data[elem] : account_data_default[elem]
|
||||
);
|
||||
for (var elem in account_data) {
|
||||
$('#account-'+elem).text(account_data[elem]);
|
||||
}
|
||||
if (account_data['is_frozen']) {
|
||||
$('#account').attr('data-balance', 'frozen');
|
||||
} else if (account_data['balance'] == '') {
|
||||
$('#account').attr('data-balance', '');
|
||||
} else if (account_data['balance'] >= 5 || account_data['trigramme'] == 'LIQ') {
|
||||
$('#account').attr('data-balance', 'ok');
|
||||
} else if (account_data['balance'] >= 0) {
|
||||
$('#account').attr('data-balance', 'low');
|
||||
} else {
|
||||
$('#account').attr('data-balance', 'neg');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +170,7 @@ $(document).ready(function() {
|
|||
|
||||
// Store data
|
||||
function storeAccountData(data) {
|
||||
account_data = data
|
||||
account_data = $.extend({}, account_data_default, data);
|
||||
$('#id_on_acc').val(account_data['pk']);
|
||||
displayAccountData();
|
||||
}
|
||||
|
@ -148,7 +189,7 @@ $(document).ready(function() {
|
|||
|
||||
// Event listener
|
||||
triInput.on('input', function() {
|
||||
var tri = triInput.val()
|
||||
var tri = triInput.val().toUpperCase();
|
||||
// Checking if tri is valid to avoid sending requests
|
||||
if (tri.match(triPattern)) {
|
||||
retrieveAccountData(tri);
|
||||
|
@ -179,10 +220,8 @@ $(document).ready(function() {
|
|||
|
||||
// Display data
|
||||
function displayCheckoutData() {
|
||||
for (var elem in checkout_data_default) {
|
||||
$('#checkout-'+elem).text(
|
||||
checkout_data[elem] ? checkout_data[elem] : checkout_data_default[elem]
|
||||
);
|
||||
for (var elem in checkout_data) {
|
||||
$('#checkout-'+elem).text(checkout_data[elem]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +234,7 @@ $(document).ready(function() {
|
|||
|
||||
// Store data
|
||||
function storeCheckoutData(data) {
|
||||
checkout_data = data;
|
||||
checkout_data = $.extend({}, checkout_data_default, data);
|
||||
$('#id_checkout').val(checkout_data['id']);
|
||||
displayCheckoutData();
|
||||
}
|
||||
|
@ -290,6 +329,8 @@ $(document).ready(function() {
|
|||
article_html.find('.'+elem).text(article[elem])
|
||||
}
|
||||
articles_container.append(article_html);
|
||||
// Pour l'autocomplétion
|
||||
articlesList.push([article['name'],article['id']]);
|
||||
}
|
||||
|
||||
function getArticlesData() {
|
||||
|
@ -305,6 +346,81 @@ $(document).ready(function() {
|
|||
});
|
||||
}
|
||||
|
||||
// -----
|
||||
// Article selection
|
||||
// -----
|
||||
|
||||
var articleSelect = $('#article_autocomplete');
|
||||
var articleId = $('#article_id');
|
||||
var articleNb = $('#article_number');
|
||||
// 8:Backspace|9:Tab|13:Enter|116:F5|117:F6|122:F11|123:F12
|
||||
var normalKeys = /^(8|9|13|116|117|122|123)$/;
|
||||
var articlesList = [];
|
||||
var articlesMatch = [];
|
||||
|
||||
function deleteNonMatching(array, str) {
|
||||
var dup = [];
|
||||
var lower_str = str.toLowerCase();
|
||||
for (var i=0; i<array.length; i++) {
|
||||
if (((array[i][0]).toLowerCase()).indexOf(lower_str) === 0)
|
||||
dup.push(array[i])
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
function callbackForPrefix(elt) {
|
||||
return elt[0].toLowerCase();
|
||||
}
|
||||
|
||||
function sharedPrefix(array) {
|
||||
var dup = array.map(callbackForPrefix);
|
||||
dup.sort(); // On trie l'array
|
||||
// On récupère le préfixe du premier et du dernier élément
|
||||
var first = dup[0], last = dup[array.length-1],
|
||||
length = first.length, i = 0;
|
||||
while (i < length && first.charAt(i) === last.charAt(i)) i++;
|
||||
return first.substring(0, i);
|
||||
}
|
||||
|
||||
articleSelect.on('keypress', function(e) {
|
||||
// Comportement normal pour ces touches
|
||||
if (normalKeys.test(e.keyCode) || e.ctrlKey) {
|
||||
if (e.keyCode == 8)
|
||||
articleId.val(0);
|
||||
if (e.charCode == 97 && e.ctrlKey) {
|
||||
articleId.val(0);
|
||||
articleSelect.val('');
|
||||
}
|
||||
return true;
|
||||
} else if (e.charCode !== 0) {
|
||||
var text = articleSelect.val();
|
||||
if (!text)
|
||||
// On part de rien donc on charge tout
|
||||
articlesMatch = articlesList.slice();
|
||||
|
||||
var articlesMatch_old = articlesMatch;
|
||||
// Filtrage des articles correspondant avec le caractère en plus
|
||||
articlesMatch = deleteNonMatching(articlesMatch_old, text + e.key.toLowerCase());
|
||||
if (articlesMatch.length == 0) {
|
||||
// Pas de résultat, cette lettre n'est pas utilisable
|
||||
// On refuse et on restaure articlesMatch
|
||||
articlesMatch = articlesMatch_old;
|
||||
return false;
|
||||
} else if (articlesMatch.length == 1) {
|
||||
// 1 seul résultat, victoire
|
||||
articleId.val(articlesMatch[0][1]);
|
||||
articleSelect.val(articlesMatch[0][0]);
|
||||
return false;
|
||||
} else {
|
||||
articleId.val(0);
|
||||
// Plusieurs résultats, on calcule le préfixe commun
|
||||
articleSelect.val(sharedPrefix(articlesMatch));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// -----
|
||||
// History
|
||||
// -----
|
||||
|
@ -377,13 +493,11 @@ $(document).ready(function() {
|
|||
// Synchronization
|
||||
// -----
|
||||
|
||||
websocket_msg_default = {'opegroups':[],'opes':[],'checkouts':[],'articles':[]}
|
||||
|
||||
socket = new ReconnectingWebSocket("ws://" + window.location.host + "/k-fet/k-psul/");
|
||||
socket.onmessage = function(e) {
|
||||
data = JSON.parse(e.data);
|
||||
data['opegroups'] = data['opegroups'] || [];
|
||||
data['opes'] = data['opes'] || [];
|
||||
data['checkouts'] = data['checkouts'] || [];
|
||||
data['articles'] = data['articles'] || [];
|
||||
data = $.extend({}, websocket_msg_default, JSON.parse(e.data));
|
||||
|
||||
for (var i=0; i<data['opegroups'].length; i++) {
|
||||
if (data['opegroups'][i]['add']) {
|
||||
|
@ -414,9 +528,10 @@ $(document).ready(function() {
|
|||
// Initiliazing all
|
||||
// -----
|
||||
resetAccountData();
|
||||
resetCheckoutData();
|
||||
checkoutInput.change();
|
||||
getHistory();
|
||||
getArticlesData();
|
||||
articleId.val(0);
|
||||
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -417,7 +417,8 @@ def kpsul_account_data(request):
|
|||
data = { 'pk': account.pk, 'name': account.name, 'email': account.email,
|
||||
'is_cof': account.is_cof, 'promo': account.promo,
|
||||
'balance': account.balance, 'is_frozen': account.is_frozen,
|
||||
'departement': account.departement, 'nickname': account.nickname }
|
||||
'departement': account.departement, 'nickname': account.nickname,
|
||||
'trigramme': account.trigramme }
|
||||
return JsonResponse(data)
|
||||
|
||||
@permission_required('kfet.is_team')
|
||||
|
|
Loading…
Reference in a new issue