nodebb-plugin-niki-loyalty 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/library.js +15 -90
- package/package.json +1 -1
- package/static/widgets/niki-kasa-debug.html +1020 -0
- package/static/widgets/niki-kasa-isolated.html +419 -0
- package/static/widgets/niki-kasa-simple.html +623 -0
- package/static/widgets/niki-kasa-widget.html +506 -0
- package/templates/niki-kasa.tpl +54 -409
package/templates/niki-kasa.tpl
CHANGED
|
@@ -7,175 +7,43 @@
|
|
|
7
7
|
body.niki-kasa-body { background-color: #000; margin: 0; padding: 0; overflow: hidden; }
|
|
8
8
|
#content { padding: 0 !important; margin: 0 !important; width: 100% !important; background: #000; }
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
.start-view { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #111; z-index: 100; color: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: 'Poppins', sans-serif; }
|
|
10
|
+
.start-view { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(1200px 700px at 50% 10%, rgba(197,160,101,0.18), transparent 60%), linear-gradient(180deg, #0b0b0b, #111 55%, #0b0b0b); z-index: 100; color: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: 'Poppins', sans-serif; }
|
|
12
11
|
.logo-box { width: 90px; height: 90px; border-radius: 50%; border: 3px solid #C5A065; display: flex; align-items: center; justify-content: center; margin-bottom: 30px; box-shadow: 0 0 30px rgba(197, 160, 101, 0.2); background: #000; }
|
|
13
12
|
.btn-start { background: #C5A065; color: #000; padding: 18px 40px; border-radius: 14px; font-weight: 700; border: none; cursor: pointer; display: flex; align-items: center; gap: 10px; font-size: 16px; margin-bottom: 15px; width: 260px; justify-content: center; box-shadow: 0 5px 15px rgba(197, 160, 101, 0.3); }
|
|
14
13
|
.btn-hist { background: #222; color: #fff; padding: 18px 40px; border-radius: 14px; font-weight: 600; border: 1px solid #333; cursor: pointer; display: flex; align-items: center; gap: 10px; font-size: 14px; width: 260px; justify-content: center; }
|
|
14
|
+
.btn-group { display: grid; gap: 12px; }
|
|
15
15
|
|
|
16
|
-
/* KAMERA */
|
|
17
16
|
.camera-ui { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000; display: none; z-index: 200; }
|
|
18
17
|
#reader { width: 100% !important; height: 100% !important; border: none !important; }
|
|
19
18
|
#reader video { object-fit: cover !important; width: 100% !important; height: 100% !important; }
|
|
20
|
-
|
|
21
19
|
.session-bar-bg { position: absolute; top:0; left:0; width:100%; height:6px; background:rgba(255,255,255,0.2); z-index: 220; }
|
|
22
20
|
.session-bar-fill { height:100%; background:#C5A065; width:100%; transition: width 1s linear; }
|
|
23
|
-
|
|
24
21
|
.top-ctrl { position: absolute; top: 20px; left: 0; width: 100%; padding: 0 20px; display: flex; justify-content: space-between; z-index: 230; box-sizing: border-box; }
|
|
25
|
-
.badge-live { background: rgba(0,0,0,0.6); color: #C5A065; padding: 6px 14px; border-radius: 20px; font-size: 12px; font-weight: 700;
|
|
26
|
-
.btn-x { background: rgba(255,255,255,0.2); width: 40px; height: 40px; border-radius: 50%; border: none; color: #fff; cursor: pointer; font-size: 18px;
|
|
27
|
-
|
|
28
|
-
/* VİZÖR */
|
|
22
|
+
.badge-live { background: rgba(0,0,0,0.6); color: #C5A065; padding: 6px 14px; border-radius: 20px; font-size: 12px; font-weight: 700; }
|
|
23
|
+
.btn-x { background: rgba(255,255,255,0.2); width: 40px; height: 40px; border-radius: 50%; border: none; color: #fff; cursor: pointer; font-size: 18px; display:flex; align-items:center; justify-content:center; }
|
|
29
24
|
.scan-guide { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 70vw; height: 70vw; max-width: 300px; max-height: 300px; box-shadow: 0 0 0 4000px rgba(0,0,0,0.85); border: 2px solid rgba(255,255,255,0.3); border-radius: 24px; pointer-events: none; z-index: 210; }
|
|
30
|
-
.scan-guide::before { content:''; position:absolute; top:-2px; left:-2px; width:40px; height:40px; border-top:5px solid #C5A065; border-left:5px solid #C5A065; border-radius:20px 0 0 0; }
|
|
31
|
-
.scan-guide::after { content:''; position:absolute; bottom:-2px; right:-2px; width:40px; height:40px; border-bottom:5px solid #C5A065; border-right:5px solid #C5A065; border-radius:0 0 20px 0; }
|
|
32
25
|
.laser { width: 100%; height: 2px; background: #C5A065; position: absolute; top: 50%; box-shadow: 0 0 15px #C5A065; animation: scanAnim 2s infinite ease-in-out; }
|
|
33
26
|
@keyframes scanAnim { 0% { top: 10%; opacity: 0; } 50% { opacity: 1; } 100% { top: 90%; opacity: 0; } }
|
|
27
|
+
.scan-hint { position: absolute; bottom: 60px; width: 100%; text-align: center; color: #fff; font-size: 13px; opacity: 0.8; z-index: 220; }
|
|
34
28
|
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
/* SONUÇ */
|
|
38
|
-
.res-modal { position: fixed; bottom: 0; left: 0; width: 100%; background: #1a1a1a; border-radius: 30px 30px 0 0; padding: 40px 20px; text-align: center; transform: translateY(110%); transition: transform 0.3s; z-index: 600; box-sizing: border-box; border-top: 1px solid #333; }
|
|
29
|
+
.res-modal { position: fixed; bottom: 0; left: 0; width: 100%; background: #1a1a1a; border-radius: 30px 30px 0 0; padding: 40px 20px; text-align: center; transform: translateY(110%); transition: transform 0.3s; z-index: 600; box-sizing: border-box; }
|
|
39
30
|
.res-modal.active { transform: translateY(0); }
|
|
40
31
|
.icon-big { font-size: 60px; margin-bottom: 15px; }
|
|
41
32
|
.res-title { color: #fff; font-size: 24px; font-weight: 700; margin-bottom: 10px; }
|
|
42
33
|
.res-msg { color: #aaa; font-size: 15px; margin-bottom: 30px; }
|
|
43
34
|
.btn-new { background: #fff; color: #000; width: 100%; padding: 18px; border-radius: 16px; font-size: 16px; font-weight: 700; border: none; cursor: pointer; }
|
|
44
35
|
|
|
45
|
-
|
|
46
|
-
.hist-
|
|
47
|
-
.hist-head {
|
|
48
|
-
.hist-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
.hist-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; padding: 16px 20px; background: #0f0f0f; border-bottom: 1px solid #1a1a1a; }
|
|
52
|
-
.stat-card { background: linear-gradient(145deg, #1a1a1a, #141414); border-radius: 14px; padding: 14px 12px; text-align: center; border: 1px solid #222; }
|
|
53
|
-
.stat-value { font-size: 24px; font-weight: 700; color: #C5A065; margin-bottom: 4px; }
|
|
54
|
-
.stat-label { font-size: 11px; color: #777; text-transform: uppercase; letter-spacing: 0.5px; }
|
|
55
|
-
|
|
56
|
-
/* FİLTRELER */
|
|
57
|
-
.hist-filters { padding: 14px 20px; background: #0d0d0d; border-bottom: 1px solid #1a1a1a; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
|
|
58
|
-
.filter-group { display: flex; flex-direction: column; gap: 4px; }
|
|
59
|
-
.filter-group label { font-size: 10px; color: #666; text-transform: uppercase; letter-spacing: 0.5px; }
|
|
60
|
-
.filter-input { background: #1a1a1a; border: 1px solid #2a2a2a; border-radius: 10px; padding: 10px 14px; color: #fff; font-size: 13px; min-width: 130px; }
|
|
61
|
-
.filter-input:focus { outline: none; border-color: #C5A065; }
|
|
62
|
-
.filter-input::placeholder { color: #555; }
|
|
63
|
-
|
|
64
|
-
.filter-select { background: #1a1a1a; border: 1px solid #2a2a2a; border-radius: 10px; padding: 10px 14px; color: #fff; font-size: 13px; min-width: 140px; cursor: pointer; }
|
|
65
|
-
.filter-select:focus { outline: none; border-color: #C5A065; }
|
|
66
|
-
|
|
67
|
-
.filter-btn { background: #C5A065; color: #000; border: none; border-radius: 10px; padding: 10px 16px; font-weight: 600; font-size: 13px; cursor: pointer; display: flex; align-items: center; gap: 6px; }
|
|
68
|
-
.filter-btn:hover { filter: brightness(1.1); }
|
|
69
|
-
.filter-btn.secondary { background: #2a2a2a; color: #fff; }
|
|
70
|
-
.filter-btn.secondary:hover { background: #333; }
|
|
71
|
-
|
|
72
|
-
/* CSV BUTONLARI */
|
|
73
|
-
.action-buttons { margin-left: auto; display: flex; gap: 8px; }
|
|
74
|
-
.btn-csv { background: linear-gradient(145deg, #2E7D32, #1B5E20); color: #fff; border: none; border-radius: 10px; padding: 10px 16px; font-weight: 600; font-size: 13px; cursor: pointer; display: flex; align-items: center; gap: 6px; }
|
|
75
|
-
.btn-csv:hover { filter: brightness(1.1); }
|
|
76
|
-
|
|
77
|
-
/* LİSTE */
|
|
78
|
-
.hist-body { flex: 1; overflow-y: auto; padding: 10px 0; }
|
|
79
|
-
.hist-row { display: flex; align-items: center; padding: 14px 20px; margin: 8px 16px; border-radius: 14px; background: linear-gradient(145deg, #161616, #121212); border: 1px solid #1f1f1f; transition: transform 0.15s, border-color 0.15s; }
|
|
80
|
-
.hist-row:hover { transform: translateX(4px); border-color: #333; }
|
|
81
|
-
.hist-u-img { width: 48px; height: 48px; border-radius: 50%; margin-right: 14px; border: 2px solid #2a2a2a; object-fit: cover; background: #1a1a1a; }
|
|
36
|
+
.hist-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #111; z-index: 700; display: none; flex-direction: column; font-family: 'Poppins', sans-serif; }
|
|
37
|
+
.hist-head { padding: 20px; background: #1a1a1a; color: #fff; display: flex; justify-content: space-between; align-items: center; }
|
|
38
|
+
.hist-head-title { font-weight: 700; font-size: 18px; }
|
|
39
|
+
.hist-body { flex: 1; overflow-y: auto; padding: 10px; }
|
|
40
|
+
.hist-row { display: flex; align-items: center; padding: 15px; margin-bottom: 10px; border-radius: 12px; background: #1a1a1a; }
|
|
41
|
+
.hist-u-img { width: 50px; height: 50px; border-radius: 50%; margin-right: 15px; object-fit: cover; }
|
|
82
42
|
.hist-info { flex: 1; }
|
|
83
|
-
.hist-u-name {
|
|
84
|
-
.hist-
|
|
85
|
-
.hist-
|
|
86
|
-
.hist-
|
|
87
|
-
.hist-reward-badge { font-size: 11px; color: #C5A065; background: rgba(197, 160, 101, 0.15); padding: 3px 8px; border-radius: 6px; border: 1px solid rgba(197, 160, 101, 0.3); }
|
|
88
|
-
.hist-val { background: rgba(198,40,40,0.15); border: 1px solid rgba(198,40,40,0.3); color: #ef5350; padding: 10px 14px; border-radius: 12px; font-size: 14px; font-weight: 700; min-width: 70px; text-align: center; }
|
|
89
|
-
|
|
90
|
-
/* BOŞ DURUM */
|
|
91
|
-
.hist-empty { text-align: center; padding: 60px 20px; color: #555; }
|
|
92
|
-
.hist-empty i { font-size: 48px; margin-bottom: 16px; display: block; opacity: 0.5; }
|
|
93
|
-
|
|
94
|
-
/* LOADING */
|
|
95
|
-
.hist-loading { text-align: center; padding: 40px; color: #666; }
|
|
96
|
-
.hist-loading .spinner { display: inline-block; width: 30px; height: 30px; border: 3px solid #333; border-top-color: #C5A065; border-radius: 50%; animation: spin 1s linear infinite; }
|
|
97
|
-
@keyframes spin { to { transform: rotate(360deg); } }
|
|
98
|
-
|
|
99
|
-
/* =========================
|
|
100
|
-
UI/UX OVERRIDES
|
|
101
|
-
========================= */
|
|
102
|
-
body.niki-kasa-body { -webkit-font-smoothing: antialiased; touch-action: manipulation; }
|
|
103
|
-
#content { min-height: 100vh; }
|
|
104
|
-
|
|
105
|
-
.start-view, .camera-ui, .hist-modal {
|
|
106
|
-
padding-top: env(safe-area-inset-top);
|
|
107
|
-
padding-bottom: env(safe-area-inset-bottom);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.start-view {
|
|
111
|
-
background: radial-gradient(1200px 700px at 50% 10%, rgba(197,160,101,0.18), transparent 60%),
|
|
112
|
-
linear-gradient(180deg, #0b0b0b, #111 55%, #0b0b0b);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.btn-group { display: grid; gap: 12px; }
|
|
116
|
-
|
|
117
|
-
.btn-start, .btn-hist, .btn-new, .btn-x { -webkit-tap-highlight-color: transparent; }
|
|
118
|
-
.btn-start:active, .btn-hist:active, .btn-new:active, .btn-x:active { transform: scale(0.97); }
|
|
119
|
-
|
|
120
|
-
.btn-start { width: min(320px, 88vw); border-radius: 16px; transition: transform 120ms ease; }
|
|
121
|
-
.btn-hist { width: min(320px, 88vw); border-radius: 16px; transition: transform 120ms ease; }
|
|
122
|
-
|
|
123
|
-
.top-ctrl { top: calc(14px + env(safe-area-inset-top)); padding: 0 16px; }
|
|
124
|
-
.btn-x { border: 1px solid rgba(255,255,255,0.15); }
|
|
125
|
-
|
|
126
|
-
.scan-guide { width: min(76vw, 320px); height: min(76vw, 320px); box-shadow: 0 0 0 5000px rgba(0,0,0,0.78); }
|
|
127
|
-
.scan-hint { bottom: calc(56px + env(safe-area-inset-bottom)); }
|
|
128
|
-
|
|
129
|
-
.res-modal {
|
|
130
|
-
background: linear-gradient(180deg, #1c1c1c, #121212);
|
|
131
|
-
border-top: 1px solid rgba(255,255,255,0.1);
|
|
132
|
-
box-shadow: 0 -20px 50px rgba(0,0,0,0.6);
|
|
133
|
-
padding-bottom: calc(20px + env(safe-area-inset-bottom));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.res-modal::before {
|
|
137
|
-
content: "";
|
|
138
|
-
display: block;
|
|
139
|
-
width: 44px;
|
|
140
|
-
height: 5px;
|
|
141
|
-
background: rgba(255,255,255,0.18);
|
|
142
|
-
border-radius: 99px;
|
|
143
|
-
margin: -10px auto 16px;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.res-close {
|
|
147
|
-
position: absolute;
|
|
148
|
-
top: 14px;
|
|
149
|
-
right: 14px;
|
|
150
|
-
width: 42px;
|
|
151
|
-
height: 42px;
|
|
152
|
-
border-radius: 50%;
|
|
153
|
-
background: rgba(255,255,255,0.12);
|
|
154
|
-
border: 1px solid rgba(255,255,255,0.18);
|
|
155
|
-
color: #fff;
|
|
156
|
-
display:flex;
|
|
157
|
-
align-items:center;
|
|
158
|
-
justify-content:center;
|
|
159
|
-
cursor:pointer;
|
|
160
|
-
backdrop-filter: blur(6px);
|
|
161
|
-
}
|
|
162
|
-
.res-close:active { transform: scale(0.95); }
|
|
163
|
-
|
|
164
|
-
.hist-body { padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
|
|
165
|
-
|
|
166
|
-
@media (prefers-reduced-motion: reduce) {
|
|
167
|
-
.laser { animation: none; }
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/* Mobil Uyum */
|
|
171
|
-
@media (max-width: 600px) {
|
|
172
|
-
.hist-stats { grid-template-columns: repeat(2, 1fr); }
|
|
173
|
-
.hist-filters { flex-direction: column; align-items: stretch; }
|
|
174
|
-
.filter-group { width: 100%; }
|
|
175
|
-
.filter-input, .filter-select { width: 100%; }
|
|
176
|
-
.action-buttons { width: 100%; justify-content: stretch; margin-left: 0; margin-top: 8px; }
|
|
177
|
-
.action-buttons .btn-csv { flex: 1; justify-content: center; }
|
|
178
|
-
}
|
|
43
|
+
.hist-u-name { font-weight: 700; font-size: 15px; color: #fff; }
|
|
44
|
+
.hist-time { font-size: 12px; color: #888; display: block; margin-top: 3px; }
|
|
45
|
+
.hist-val { background: rgba(198,40,40,0.2); color: #ef5350; padding: 8px 14px; border-radius: 10px; font-weight: 700; }
|
|
46
|
+
.hist-empty { text-align: center; padding: 60px; color: #666; }
|
|
179
47
|
</style>
|
|
180
48
|
|
|
181
49
|
<div id="start-view" class="start-view">
|
|
@@ -200,106 +68,43 @@
|
|
|
200
68
|
</div>
|
|
201
69
|
|
|
202
70
|
<div id="res-view" class="res-modal">
|
|
203
|
-
<button class="res-close" onclick="stopSession()" aria-label="Kapat">
|
|
204
|
-
<i class="fa fa-times"></i>
|
|
205
|
-
</button>
|
|
206
71
|
<div id="res-icon" class="icon-big"></div>
|
|
207
72
|
<div id="res-title" class="res-title">...</div>
|
|
208
73
|
<div id="res-msg" class="res-msg">...</div>
|
|
209
74
|
<button class="btn-new" onclick="resumeScan()">YENİ İŞLEM</button>
|
|
210
75
|
</div>
|
|
211
76
|
|
|
212
|
-
<!-- GELİŞMİŞ İŞLEM GEÇMİŞİ -->
|
|
213
77
|
<div id="hist-view" class="hist-modal">
|
|
214
78
|
<div class="hist-head">
|
|
215
79
|
<span class="hist-head-title"><i class="fa fa-history"></i> İŞLEM GEÇMİŞİ</span>
|
|
216
80
|
<button onclick="closeHistory()" style="background:none; border:none; color:#fff; font-size:20px; cursor:pointer;"><i class="fa fa-times"></i></button>
|
|
217
81
|
</div>
|
|
218
|
-
|
|
219
|
-
<!-- İSTATİSTİKLER -->
|
|
220
|
-
<div class="hist-stats">
|
|
221
|
-
<div class="stat-card">
|
|
222
|
-
<div class="stat-value" id="stat-total">0</div>
|
|
223
|
-
<div class="stat-label">Toplam İşlem</div>
|
|
224
|
-
</div>
|
|
225
|
-
<div class="stat-card">
|
|
226
|
-
<div class="stat-value" id="stat-points">0</div>
|
|
227
|
-
<div class="stat-label">Toplam Puan</div>
|
|
228
|
-
</div>
|
|
229
|
-
<div class="stat-card">
|
|
230
|
-
<div class="stat-value" id="stat-today">0</div>
|
|
231
|
-
<div class="stat-label">Bugün</div>
|
|
232
|
-
</div>
|
|
233
|
-
</div>
|
|
234
|
-
|
|
235
|
-
<!-- FİLTRELER -->
|
|
236
|
-
<div class="hist-filters">
|
|
237
|
-
<div class="filter-group">
|
|
238
|
-
<label>Başlangıç</label>
|
|
239
|
-
<input type="date" class="filter-input" id="filter-start">
|
|
240
|
-
</div>
|
|
241
|
-
<div class="filter-group">
|
|
242
|
-
<label>Bitiş</label>
|
|
243
|
-
<input type="date" class="filter-input" id="filter-end">
|
|
244
|
-
</div>
|
|
245
|
-
<div class="filter-group">
|
|
246
|
-
<label>Ara</label>
|
|
247
|
-
<input type="text" class="filter-input" id="filter-search" placeholder="Kullanıcı adı...">
|
|
248
|
-
</div>
|
|
249
|
-
<div class="filter-group">
|
|
250
|
-
<label>Ödül Tipi</label>
|
|
251
|
-
<select class="filter-select" id="filter-reward">
|
|
252
|
-
<option value="all">Tümü</option>
|
|
253
|
-
</select>
|
|
254
|
-
</div>
|
|
255
|
-
<button class="filter-btn" onclick="applyFilters()"><i class="fa fa-filter"></i> Filtrele</button>
|
|
256
|
-
<button class="filter-btn secondary" onclick="clearFilters()"><i class="fa fa-refresh"></i> Sıfırla</button>
|
|
257
|
-
|
|
258
|
-
<div class="action-buttons">
|
|
259
|
-
<button class="btn-csv" onclick="exportCSV()"><i class="fa fa-download"></i> CSV İndir</button>
|
|
260
|
-
</div>
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
<!-- LİSTE -->
|
|
264
|
-
<ul id="hist-list" class="hist-body"></ul>
|
|
82
|
+
<ul id="hist-list" class="hist-body" style="list-style:none; margin:0; padding:10px;"></ul>
|
|
265
83
|
</div>
|
|
266
84
|
|
|
267
|
-
<div id="denied" style="display:none; text-align:center; padding:100px; color:#fff;"><h3>Yetkisiz Giriş</h3></div>
|
|
268
|
-
|
|
269
85
|
<script>
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
let currentHistoryData = [];
|
|
86
|
+
var html5QrCode;
|
|
87
|
+
var isProcessing = false;
|
|
88
|
+
var sessionTimer;
|
|
274
89
|
moment.locale('tr');
|
|
275
90
|
|
|
276
|
-
// --- ARKA KAMERA BULMA VE BAŞLATMA ---
|
|
277
91
|
async function initSession() {
|
|
278
92
|
$('#start-view').fadeOut(200);
|
|
279
93
|
$('#camera-ui').fadeIn(300);
|
|
280
94
|
startTimer(600);
|
|
281
|
-
|
|
282
95
|
html5QrCode = new Html5Qrcode("reader");
|
|
283
|
-
|
|
284
96
|
try {
|
|
285
|
-
|
|
286
|
-
|
|
97
|
+
var devices = await Html5Qrcode.getCameras();
|
|
287
98
|
if (devices && devices.length) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
let label = devices[i].label.toLowerCase();
|
|
99
|
+
var cameraId = devices[devices.length - 1].id;
|
|
100
|
+
for (var i = 0; i < devices.length; i++) {
|
|
101
|
+
var label = devices[i].label.toLowerCase();
|
|
292
102
|
if (label.includes("back") || label.includes("arka") || label.includes("environment")) {
|
|
293
103
|
cameraId = devices[i].id;
|
|
294
104
|
break;
|
|
295
105
|
}
|
|
296
106
|
}
|
|
297
|
-
|
|
298
|
-
await html5QrCode.start(
|
|
299
|
-
cameraId,
|
|
300
|
-
{ fps: 15, aspectRatio: window.innerWidth / window.innerHeight },
|
|
301
|
-
onScanSuccess
|
|
302
|
-
);
|
|
107
|
+
await html5QrCode.start(cameraId, { fps: 15, aspectRatio: window.innerWidth / window.innerHeight }, onScanSuccess);
|
|
303
108
|
} else {
|
|
304
109
|
alert("Kamera bulunamadı!");
|
|
305
110
|
stopSession();
|
|
@@ -311,12 +116,12 @@
|
|
|
311
116
|
}
|
|
312
117
|
|
|
313
118
|
function startTimer(duration) {
|
|
314
|
-
|
|
119
|
+
var timeLeft = duration;
|
|
315
120
|
$('#timer-bar').css('width', '100%');
|
|
316
121
|
clearInterval(sessionTimer);
|
|
317
|
-
sessionTimer = setInterval(()
|
|
122
|
+
sessionTimer = setInterval(function() {
|
|
318
123
|
timeLeft--;
|
|
319
|
-
|
|
124
|
+
var pct = (timeLeft / duration) * 100;
|
|
320
125
|
$('#timer-bar').css('width', pct + '%');
|
|
321
126
|
if(timeLeft <= 0) { alert("Oturum doldu."); stopSession(); }
|
|
322
127
|
}, 1000);
|
|
@@ -325,224 +130,70 @@
|
|
|
325
130
|
function onScanSuccess(decodedText) {
|
|
326
131
|
if (isProcessing) return;
|
|
327
132
|
isProcessing = true;
|
|
328
|
-
|
|
329
|
-
const audio = new Audio('https://freesound.org/data/previews/171/171671_2437358-lq.mp3');
|
|
330
|
-
audio.play().catch(e=>{});
|
|
331
133
|
if(navigator.vibrate) navigator.vibrate(200);
|
|
332
|
-
|
|
333
134
|
html5QrCode.pause();
|
|
334
135
|
|
|
335
136
|
$.post('/api/niki-loyalty/scan-qr', { token: decodedText, _csrf: config.csrf_token }, function(res) {
|
|
336
137
|
if(res.success) {
|
|
337
138
|
$('#res-icon').html('<i class="fa fa-check-circle" style="color:#2E7D32"></i>');
|
|
338
139
|
$('#res-title').text('ÖDEME ALINDI');
|
|
339
|
-
$('#res-msg').html(
|
|
340
|
-
<img src="${res.customer.picture || ''}" style="width:60px; height:60px; border-radius:50%; border:2px solid #fff; margin-bottom:10px;"><br>
|
|
341
|
-
<b>${res.customer.username}</b><br>
|
|
342
|
-
${res.cost} Puan Tahsil Edildi.<br>
|
|
343
|
-
<small style="color:#C5A065">${res.rewardName}</small>
|
|
344
|
-
`);
|
|
140
|
+
$('#res-msg').html('<b>'+res.customer.username+'</b><br>'+res.cost+' Puan Tahsil Edildi.');
|
|
345
141
|
} else {
|
|
346
|
-
new Audio('https://freesound.org/data/previews/142/142608_1840739-lq.mp3').play().catch(e=>{});
|
|
347
|
-
if(navigator.vibrate) navigator.vibrate([100,50,100]);
|
|
348
142
|
$('#res-icon').html('<i class="fa fa-times-circle" style="color:#C62828"></i>');
|
|
349
143
|
$('#res-title').text('HATA');
|
|
350
144
|
$('#res-msg').text(res.message);
|
|
351
145
|
}
|
|
352
146
|
$('#res-view').addClass('active');
|
|
353
|
-
}).fail(function() {
|
|
354
|
-
alert("Sunucu Hatası!"); resumeScan();
|
|
355
|
-
});
|
|
147
|
+
}).fail(function() { alert("Sunucu Hatası!"); resumeScan(); });
|
|
356
148
|
}
|
|
357
149
|
|
|
358
150
|
function resumeScan() {
|
|
359
151
|
$('#res-view').removeClass('active');
|
|
360
|
-
setTimeout(()
|
|
152
|
+
setTimeout(function() { isProcessing = false; html5QrCode.resume(); }, 300);
|
|
361
153
|
}
|
|
362
154
|
|
|
363
155
|
function stopSession() {
|
|
364
156
|
clearInterval(sessionTimer);
|
|
365
|
-
if(html5QrCode) html5QrCode.stop().then(()
|
|
157
|
+
if(html5QrCode) html5QrCode.stop().then(function() { html5QrCode.clear(); }).catch(function(){});
|
|
366
158
|
$('#camera-ui').hide();
|
|
367
159
|
$('#res-view').removeClass('active');
|
|
368
160
|
$('#start-view').fadeIn(200);
|
|
369
161
|
isProcessing = false;
|
|
370
162
|
}
|
|
371
163
|
|
|
372
|
-
// =============================
|
|
373
|
-
// GELİŞMİŞ İŞLEM GEÇMİŞİ
|
|
374
|
-
// =============================
|
|
375
|
-
|
|
376
164
|
function openHistory() {
|
|
377
165
|
$('#hist-view').fadeIn().css('display','flex');
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
function closeHistory() {
|
|
382
|
-
$('#hist-view').fadeOut();
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function loadHistory(filters = {}) {
|
|
386
|
-
const list = $('#hist-list');
|
|
387
|
-
list.html('<li class="hist-loading"><div class="spinner"></div><br>Yükleniyor...</li>');
|
|
166
|
+
var list = $('#hist-list');
|
|
167
|
+
list.html('<li style="text-align:center; padding:40px; color:#888;">Yükleniyor...</li>');
|
|
388
168
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (filters.search) params.append('search', filters.search);
|
|
393
|
-
if (filters.rewardType) params.append('rewardType', filters.rewardType);
|
|
394
|
-
|
|
395
|
-
$.get('/api/niki-loyalty/kasa-history?' + params.toString(), function(response) {
|
|
396
|
-
if (response.error) {
|
|
397
|
-
list.html('<li class="hist-empty"><i class="fa fa-exclamation-circle"></i>Hata: ' + response.error + '</li>');
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
169
|
+
$.get('/api/niki-loyalty/kasa-history', function(response) {
|
|
170
|
+
// Hem eski (array) hem yeni ({data:[]}) formatı destekle
|
|
171
|
+
var data = Array.isArray(response) ? response : (response.data || []);
|
|
400
172
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const rewardTypes = response.rewardTypes || [];
|
|
404
|
-
|
|
405
|
-
currentHistoryData = data;
|
|
406
|
-
|
|
407
|
-
// İstatistikleri güncelle
|
|
408
|
-
$('#stat-total').text(stats.totalTransactions || 0);
|
|
409
|
-
$('#stat-points').text((stats.totalPoints || 0).toLocaleString('tr-TR'));
|
|
410
|
-
|
|
411
|
-
// Bugünkü işlem sayısı
|
|
412
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
413
|
-
$('#stat-today').text(stats.byDate[today] || 0);
|
|
414
|
-
|
|
415
|
-
// Ödül tipi dropdown'ını doldur
|
|
416
|
-
const rewardSelect = $('#filter-reward');
|
|
417
|
-
const currentVal = rewardSelect.val();
|
|
418
|
-
rewardSelect.html('<option value="all">Tümü</option>');
|
|
419
|
-
rewardTypes.forEach(type => {
|
|
420
|
-
rewardSelect.append(`<option value="${type}">${type}</option>`);
|
|
421
|
-
});
|
|
422
|
-
if (currentVal) rewardSelect.val(currentVal);
|
|
423
|
-
|
|
424
|
-
// Listeyi render et
|
|
425
|
-
renderHistoryList(data);
|
|
426
|
-
|
|
427
|
-
}).fail(function() {
|
|
428
|
-
list.html('<li class="hist-empty"><i class="fa fa-wifi"></i>Bağlantı hatası</li>');
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
function renderHistoryList(data) {
|
|
433
|
-
const list = $('#hist-list');
|
|
434
|
-
list.empty();
|
|
435
|
-
|
|
436
|
-
if (!data || data.length === 0) {
|
|
437
|
-
list.html('<li class="hist-empty"><i class="fa fa-inbox"></i>İşlem bulunamadı</li>');
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
data.forEach(item => {
|
|
442
|
-
const timeAgo = moment(item.ts).fromNow();
|
|
443
|
-
const exactTime = moment(item.ts).format('DD MMM YYYY, HH:mm');
|
|
444
|
-
|
|
445
|
-
const html = `
|
|
446
|
-
<li class="hist-row">
|
|
447
|
-
<img src="${item.picture || 'https://via.placeholder.com/50'}" class="hist-u-img" onerror="this.src='https://via.placeholder.com/50'">
|
|
448
|
-
<div class="hist-info">
|
|
449
|
-
<span class="hist-u-name">${escapeHtml(item.cust)}</span>
|
|
450
|
-
<div class="hist-meta">
|
|
451
|
-
<span class="hist-time" title="${exactTime}">${timeAgo}</span>
|
|
452
|
-
<span class="hist-staff"><i class="fa fa-user-circle"></i> ${escapeHtml(item.staffName)}</span>
|
|
453
|
-
<span class="hist-reward-badge">${escapeHtml(item.reward)}</span>
|
|
454
|
-
</div>
|
|
455
|
-
</div>
|
|
456
|
-
<div class="hist-val">-${item.amt || 0}</div>
|
|
457
|
-
</li>
|
|
458
|
-
`;
|
|
459
|
-
list.append(html);
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function applyFilters() {
|
|
464
|
-
const filters = {
|
|
465
|
-
startDate: $('#filter-start').val(),
|
|
466
|
-
endDate: $('#filter-end').val(),
|
|
467
|
-
search: $('#filter-search').val(),
|
|
468
|
-
rewardType: $('#filter-reward').val()
|
|
469
|
-
};
|
|
470
|
-
loadHistory(filters);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
function clearFilters() {
|
|
474
|
-
$('#filter-start').val('');
|
|
475
|
-
$('#filter-end').val('');
|
|
476
|
-
$('#filter-search').val('');
|
|
477
|
-
$('#filter-reward').val('all');
|
|
478
|
-
loadHistory();
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
function exportCSV() {
|
|
482
|
-
// Mevcut filtrelerle tüm veriyi al
|
|
483
|
-
const filters = {
|
|
484
|
-
startDate: $('#filter-start').val(),
|
|
485
|
-
endDate: $('#filter-end').val(),
|
|
486
|
-
search: $('#filter-search').val(),
|
|
487
|
-
rewardType: $('#filter-reward').val()
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
const params = new URLSearchParams();
|
|
491
|
-
if (filters.startDate) params.append('startDate', filters.startDate);
|
|
492
|
-
if (filters.endDate) params.append('endDate', filters.endDate);
|
|
493
|
-
if (filters.search) params.append('search', filters.search);
|
|
494
|
-
if (filters.rewardType) params.append('rewardType', filters.rewardType);
|
|
495
|
-
params.append('exportAll', 'true');
|
|
496
|
-
|
|
497
|
-
$.get('/api/niki-loyalty/kasa-history?' + params.toString(), function(response) {
|
|
498
|
-
if (response.error) {
|
|
499
|
-
alert('CSV oluşturulamadı: ' + response.error);
|
|
173
|
+
if(data.length === 0) {
|
|
174
|
+
list.html('<li class="hist-empty"><i class="fa fa-inbox" style="font-size:40px; display:block; margin-bottom:15px;"></i>İşlem bulunamadı</li>');
|
|
500
175
|
return;
|
|
501
176
|
}
|
|
502
177
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
date.format('DD.MM.YYYY'),
|
|
515
|
-
date.format('HH:mm:ss'),
|
|
516
|
-
'"' + (item.cust || '').replace(/"/g, '""') + '"',
|
|
517
|
-
'"' + (item.staffName || '').replace(/"/g, '""') + '"',
|
|
518
|
-
'"' + (item.reward || '').replace(/"/g, '""') + '"',
|
|
519
|
-
item.amt || 0
|
|
520
|
-
].join(';');
|
|
178
|
+
list.empty();
|
|
179
|
+
data.forEach(function(item) {
|
|
180
|
+
var html = '<li class="hist-row">' +
|
|
181
|
+
'<img src="'+(item.picture || 'https://via.placeholder.com/50')+'" class="hist-u-img" onerror="this.src=\'https://via.placeholder.com/50\'">' +
|
|
182
|
+
'<div class="hist-info">' +
|
|
183
|
+
'<span class="hist-u-name">'+(item.cust || 'Bilinmeyen')+'</span>' +
|
|
184
|
+
'<span class="hist-time">'+moment(item.ts).fromNow()+'</span>' +
|
|
185
|
+
'</div>' +
|
|
186
|
+
'<div class="hist-val">-'+(item.amt || 250)+'</div>' +
|
|
187
|
+
'</li>';
|
|
188
|
+
list.append(html);
|
|
521
189
|
});
|
|
522
|
-
|
|
523
|
-
const csv = '\uFEFF' + headers.join(';') + '\n' + rows.join('\n');
|
|
524
|
-
|
|
525
|
-
// İndir
|
|
526
|
-
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
|
527
|
-
const url = URL.createObjectURL(blob);
|
|
528
|
-
const link = document.createElement('a');
|
|
529
|
-
link.href = url;
|
|
530
|
-
link.download = `niki-kasa-${moment().format('YYYY-MM-DD')}.csv`;
|
|
531
|
-
document.body.appendChild(link);
|
|
532
|
-
link.click();
|
|
533
|
-
document.body.removeChild(link);
|
|
534
|
-
URL.revokeObjectURL(url);
|
|
535
|
-
|
|
536
190
|
}).fail(function() {
|
|
537
|
-
|
|
191
|
+
list.html('<li class="hist-empty">Bağlantı hatası</li>');
|
|
538
192
|
});
|
|
539
193
|
}
|
|
540
|
-
|
|
541
|
-
function
|
|
542
|
-
|
|
543
|
-
const div = document.createElement('div');
|
|
544
|
-
div.textContent = text;
|
|
545
|
-
return div.innerHTML;
|
|
194
|
+
|
|
195
|
+
function closeHistory() {
|
|
196
|
+
$('#hist-view').fadeOut();
|
|
546
197
|
}
|
|
547
198
|
|
|
548
199
|
$(document).ready(function() {
|
|
@@ -550,12 +201,6 @@
|
|
|
550
201
|
$('.start-view').remove();
|
|
551
202
|
$('body').html('<div style="text-align:center; padding:50px; color:#fff;"><h3>⛔ Yetkisiz Giriş</h3></div>');
|
|
552
203
|
}
|
|
553
|
-
|
|
554
|
-
// Varsayılan tarih aralığını ayarla (son 30 gün)
|
|
555
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
556
|
-
const monthAgo = new Date(Date.now() - 30*24*60*60*1000).toISOString().slice(0, 10);
|
|
557
|
-
$('#filter-end').val(today);
|
|
558
|
-
$('#filter-start').val(monthAgo);
|
|
559
204
|
});
|
|
560
205
|
|
|
561
206
|
$(window).on('action:ajaxify.start', function() { stopSession(); closeHistory(); });
|