create-devoplus-one-app 0.0.0-stage → 0.1.0-next.158
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/README.md +62 -2
- package/dist/cli.mjs +17 -0
- package/package.json +35 -3
- package/templates/0001_init.sql.tpl +10 -0
- package/templates/AGENTS.md.tpl +286 -0
- package/templates/AGENT_GUIDE.md.tpl +36 -0
- package/templates/README.md.tpl +58 -0
- package/templates/_shared/AGENTS.writes.md.tpl +38 -0
- package/templates/_shared/README.tail.md.tpl +20 -0
- package/templates/_shared/files/src/app.test.ts.tpl +36 -0
- package/templates/_shared/files/src/index.ts.tpl +8 -0
- package/templates/_shared/files/src/lib/client.ts.tpl +213 -0
- package/templates/_shared/files/src/lib/files.ts.tpl +37 -0
- package/templates/_shared/files/src/lib/http.ts.tpl +101 -0
- package/templates/_shared/files/src/lib/mail.ts.tpl +26 -0
- package/templates/_shared/files/src/lib/model.ts.tpl +31 -0
- package/templates/_shared/files/src/lib/page.ts.tpl +71 -0
- package/templates/_shared/files/src/lib/record.ts.tpl +246 -0
- package/templates/_shared/files/src/lib/server.ts.tpl +132 -0
- package/templates/_shared/files/src/shell.test.ts.tpl +56 -0
- package/templates/agent.ts.tpl +23 -0
- package/templates/bakim-takvimi/AGENTS.template.md.tpl +40 -0
- package/templates/bakim-takvimi/README.md.tpl +45 -0
- package/templates/bakim-takvimi/files/AGENT_GUIDE.md.tpl +52 -0
- package/templates/bakim-takvimi/files/one.data.json +45 -0
- package/templates/bakim-takvimi/files/src/agent.ts.tpl +22 -0
- package/templates/bakim-takvimi/files/src/app.ts.tpl +259 -0
- package/templates/bakim-takvimi/files/src/jobs.ts.tpl +170 -0
- package/templates/bakim-takvimi/files/src/names.ts.tpl +5 -0
- package/templates/bakim-takvimi/files/src/queries.ts.tpl +71 -0
- package/templates/bakim-takvimi/files/src/schedule.test.ts.tpl +58 -0
- package/templates/bakim-takvimi/files/src/schedule.ts.tpl +106 -0
- package/templates/bakim-takvimi/files/src/shell.ts.tpl +299 -0
- package/templates/bakim-takvimi/manifest.json.tpl +64 -0
- package/templates/egitim-sertifika/AGENTS.template.md.tpl +41 -0
- package/templates/egitim-sertifika/README.md.tpl +46 -0
- package/templates/egitim-sertifika/files/AGENT_GUIDE.md.tpl +53 -0
- package/templates/egitim-sertifika/files/one.data.json +43 -0
- package/templates/egitim-sertifika/files/src/agent.ts.tpl +22 -0
- package/templates/egitim-sertifika/files/src/app.ts.tpl +312 -0
- package/templates/egitim-sertifika/files/src/certificate.test.ts.tpl +83 -0
- package/templates/egitim-sertifika/files/src/certificate.ts.tpl +163 -0
- package/templates/egitim-sertifika/files/src/jobs.ts.tpl +219 -0
- package/templates/egitim-sertifika/files/src/names.ts.tpl +5 -0
- package/templates/egitim-sertifika/files/src/queries.ts.tpl +115 -0
- package/templates/egitim-sertifika/files/src/shell.ts.tpl +345 -0
- package/templates/egitim-sertifika/manifest.json.tpl +57 -0
- package/templates/envanter/AGENTS.template.md.tpl +28 -0
- package/templates/envanter/README.md.tpl +40 -0
- package/templates/envanter/files/AGENT_GUIDE.md.tpl +47 -0
- package/templates/envanter/files/one.data.json +62 -0
- package/templates/envanter/files/src/agent.ts.tpl +20 -0
- package/templates/envanter/files/src/app.ts.tpl +204 -0
- package/templates/envanter/files/src/jobs.ts.tpl +30 -0
- package/templates/envanter/files/src/queries.ts.tpl +53 -0
- package/templates/envanter/files/src/shell.ts.tpl +265 -0
- package/templates/envanter/files/src/stock.test.ts.tpl +31 -0
- package/templates/envanter/files/src/stock.ts.tpl +33 -0
- package/templates/envanter/manifest.json.tpl +56 -0
- package/templates/hedef-takibi/AGENTS.template.md.tpl +37 -0
- package/templates/hedef-takibi/README.md.tpl +52 -0
- package/templates/hedef-takibi/files/AGENT_GUIDE.md.tpl +48 -0
- package/templates/hedef-takibi/files/one.data.json +76 -0
- package/templates/hedef-takibi/files/src/agent.ts.tpl +26 -0
- package/templates/hedef-takibi/files/src/app.ts.tpl +740 -0
- package/templates/hedef-takibi/files/src/progress.test.ts.tpl +53 -0
- package/templates/hedef-takibi/files/src/progress.ts.tpl +81 -0
- package/templates/hedef-takibi/files/src/queries.ts.tpl +83 -0
- package/templates/hedef-takibi/files/src/shell.ts.tpl +455 -0
- package/templates/hedef-takibi/manifest.json.tpl +38 -0
- package/templates/index.ts.tpl +262 -0
- package/templates/markdown.d.ts.tpl +6 -0
- package/templates/musteri-ziyaret/AGENTS.template.md.tpl +47 -0
- package/templates/musteri-ziyaret/README.md.tpl +48 -0
- package/templates/musteri-ziyaret/files/AGENT_GUIDE.md.tpl +44 -0
- package/templates/musteri-ziyaret/files/one.data.json +53 -0
- package/templates/musteri-ziyaret/files/src/agent.ts.tpl +21 -0
- package/templates/musteri-ziyaret/files/src/app.ts.tpl +340 -0
- package/templates/musteri-ziyaret/files/src/customers.ts.tpl +85 -0
- package/templates/musteri-ziyaret/files/src/queries.ts.tpl +67 -0
- package/templates/musteri-ziyaret/files/src/shell.ts.tpl +272 -0
- package/templates/musteri-ziyaret/files/src/visit.test.ts.tpl +65 -0
- package/templates/musteri-ziyaret/files/src/visit.ts.tpl +98 -0
- package/templates/musteri-ziyaret/manifest.json.tpl +37 -0
- package/templates/saha-denetimi/AGENTS.template.md.tpl +32 -0
- package/templates/saha-denetimi/README.md.tpl +44 -0
- package/templates/saha-denetimi/files/AGENT_GUIDE.md.tpl +55 -0
- package/templates/saha-denetimi/files/one.data.json +87 -0
- package/templates/saha-denetimi/files/src/agent.ts.tpl +41 -0
- package/templates/saha-denetimi/files/src/app.ts.tpl +444 -0
- package/templates/saha-denetimi/files/src/queries.ts.tpl +143 -0
- package/templates/saha-denetimi/files/src/score.test.ts.tpl +48 -0
- package/templates/saha-denetimi/files/src/score.ts.tpl +102 -0
- package/templates/saha-denetimi/files/src/shell.ts.tpl +585 -0
- package/templates/saha-denetimi/manifest.json.tpl +49 -0
- package/templates/shell.test.ts.tpl +30 -0
- package/templates/shell.ts.tpl +201 -0
- package/templates/uygunsuzluk-dof/AGENTS.template.md.tpl +40 -0
- package/templates/uygunsuzluk-dof/README.md.tpl +46 -0
- package/templates/uygunsuzluk-dof/files/AGENT_GUIDE.md.tpl +56 -0
- package/templates/uygunsuzluk-dof/files/one.data.json +99 -0
- package/templates/uygunsuzluk-dof/files/src/agent.ts.tpl +45 -0
- package/templates/uygunsuzluk-dof/files/src/app.ts.tpl +431 -0
- package/templates/uygunsuzluk-dof/files/src/capa.test.ts.tpl +53 -0
- package/templates/uygunsuzluk-dof/files/src/capa.ts.tpl +114 -0
- package/templates/uygunsuzluk-dof/files/src/jobs.ts.tpl +127 -0
- package/templates/uygunsuzluk-dof/files/src/queries.ts.tpl +102 -0
- package/templates/uygunsuzluk-dof/files/src/shell.ts.tpl +441 -0
- package/templates/uygunsuzluk-dof/manifest.json.tpl +56 -0
- package/templates/ziyaretci-kaydi/AGENTS.template.md.tpl +35 -0
- package/templates/ziyaretci-kaydi/README.md.tpl +46 -0
- package/templates/ziyaretci-kaydi/files/AGENT_GUIDE.md.tpl +39 -0
- package/templates/ziyaretci-kaydi/files/one.data.json +42 -0
- package/templates/ziyaretci-kaydi/files/src/agent.ts.tpl +13 -0
- package/templates/ziyaretci-kaydi/files/src/app.ts.tpl +293 -0
- package/templates/ziyaretci-kaydi/files/src/jobs.ts.tpl +49 -0
- package/templates/ziyaretci-kaydi/files/src/notice.ts.tpl +48 -0
- package/templates/ziyaretci-kaydi/files/src/queries.ts.tpl +45 -0
- package/templates/ziyaretci-kaydi/files/src/shell.ts.tpl +252 -0
- package/templates/ziyaretci-kaydi/files/src/visitor.test.ts.tpl +34 -0
- package/templates/ziyaretci-kaydi/files/src/visitor.ts.tpl +57 -0
- package/templates/ziyaretci-kaydi/manifest.json.tpl +38 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
// {{nameTr}} — sayfa (üç görünüm: Denetimlerim · Pano · Kontrol listeleri) + her görünümden açılan denetim paneli.
|
|
2
|
+
// Liste, süzgeç, form, dosya yükleme ve grafik hazır bileşenlerdir; seçenekler veri modelinden gelir. Puan ve sonuç
|
|
3
|
+
// sunucuda hesaplanır; sayfa yalnız gösterir. Denetim raporu sunucunun yazdırma sayfasıdır (gizli çerçevede yazdırılır).
|
|
4
|
+
import type { OneNavigationItem } from '@devoplus/one-sdk'
|
|
5
|
+
import { dataModel } from './data/types.ts'
|
|
6
|
+
import { renderClientScript } from './lib/client.ts'
|
|
7
|
+
import { choices, label } from './lib/model.ts'
|
|
8
|
+
import { escapeHtml, i18n, renderPage, translator, view, type Lang, type Strings, type Theme } from './lib/page.ts'
|
|
9
|
+
import { NOTE_MAX, WEIGHT_MAX, WEIGHT_MIN } from './score.ts'
|
|
10
|
+
|
|
11
|
+
export const STRINGS: Strings = {
|
|
12
|
+
tr: {
|
|
13
|
+
title: {{nameTrJs}},
|
|
14
|
+
waiting: "Portal'dan oturum bekleniyor…",
|
|
15
|
+
networkError: 'İstek gönderilemedi (ağ hatası).',
|
|
16
|
+
requestFailed: 'İşlem yapılamadı.',
|
|
17
|
+
readOnly: 'Vekalet ya da Yerine Görüntüle oturumundasınız: bu uygulamada yalnız görüntüleme yapabilirsiniz.',
|
|
18
|
+
myIntro: 'Yaptığınız denetimler. Taslak denetime tıklayıp devam edebilir, tamamlanmış denetimin raporunu yazdırabilirsiniz.',
|
|
19
|
+
startTitle: 'Yeni denetim',
|
|
20
|
+
startSubmit: 'Denetimi başlat',
|
|
21
|
+
checklist: 'Kontrol listesi',
|
|
22
|
+
workplace: 'İş yeri',
|
|
23
|
+
workplaceHelp: 'Listede yoksa aşağıya yerin adını yazın.',
|
|
24
|
+
locationName: 'Yerin adı',
|
|
25
|
+
noChecklist: 'Kullanımda kontrol listesi yok. Yöneticinizden bir kontrol listesi tanımlamasını isteyin.',
|
|
26
|
+
started: 'Denetim başladı; maddeleri doldurun.',
|
|
27
|
+
myTable: 'Denetimlerim',
|
|
28
|
+
search: 'Ara',
|
|
29
|
+
managersOnly: 'Bu bölüm yalnız yöneticilere açıktır.',
|
|
30
|
+
dashSummary: 'Son 30 günde {n} denetim tamamlandı; ortalama puan {avg}. Başarısız: {failed}, kritik maddesi uygun olmayan: {critical}. Taslakta bekleyen: {drafts}.',
|
|
31
|
+
noAverage: '-',
|
|
32
|
+
chartTitle: 'Yerlere göre puan',
|
|
33
|
+
seriesLast: 'Son puan',
|
|
34
|
+
seriesAverage: 'Ortalama',
|
|
35
|
+
recentTitle: 'Son denetimler',
|
|
36
|
+
allTitle: 'Bütün denetimler',
|
|
37
|
+
printList: 'Listeyi yazdır',
|
|
38
|
+
listsIntro: 'Denetimlerde kullanılan kontrol listeleri. Bir listeye tıklayıp maddelerini düzenleyin. Madde değişikliği başlamış denetimleri etkilemez.',
|
|
39
|
+
listsTable: 'Kontrol listeleri',
|
|
40
|
+
listForm: 'Kontrol listesi bilgileri',
|
|
41
|
+
newList: 'Yeni kontrol listesi',
|
|
42
|
+
listSaved: 'Kontrol listesi kaydedildi.',
|
|
43
|
+
itemsTitle: 'Maddeler',
|
|
44
|
+
itemsHint: 'Ağırlık {min}-{max} arası bir tam sayıdır. Kritik madde uygun bulunmazsa denetim başarısız sayılır.',
|
|
45
|
+
newItem: 'Yeni madde',
|
|
46
|
+
deleteItem: 'Maddeyi sil',
|
|
47
|
+
deleteItemConfirm: '"{title}" maddesi silinsin mi? Başlamış denetimler etkilenmez.',
|
|
48
|
+
itemSaved: 'Madde kaydedildi.',
|
|
49
|
+
itemDeleted: 'Madde silindi.',
|
|
50
|
+
auditTitle: 'Denetim: {location}',
|
|
51
|
+
auditor: 'Denetçi',
|
|
52
|
+
started_at: 'Başlangıç',
|
|
53
|
+
editIntro: 'Her maddeyi değerlendirin. "Uygulanamaz" maddeler puana girmez; "uygun değil" seçtiğiniz maddeye ne gördüğünüzü yazın. Tamamladıktan sonra denetim değiştirilemez.',
|
|
54
|
+
saveDraft: 'Taslağı kaydet',
|
|
55
|
+
saved: 'Taslak kaydedildi.',
|
|
56
|
+
submitAudit: 'Denetimi tamamla',
|
|
57
|
+
submitConfirm: 'Denetim tamamlansın mı? Tamamlandıktan sonra cevaplar değiştirilemez.',
|
|
58
|
+
submitted: 'Denetim tamamlandı.',
|
|
59
|
+
deleteDraft: 'Taslağı sil',
|
|
60
|
+
deleteDraftConfirm: 'Bu taslak denetim silinsin mi?',
|
|
61
|
+
draftDeleted: 'Taslak silindi.',
|
|
62
|
+
printAudit: 'Raporu yazdır',
|
|
63
|
+
close: 'Kapat',
|
|
64
|
+
critical: 'kritik',
|
|
65
|
+
itemHelp: 'Bölüm: {section} - Ağırlık: {weight}',
|
|
66
|
+
note: 'Not',
|
|
67
|
+
photo: 'Fotoğraf',
|
|
68
|
+
generalNote: 'Genel not',
|
|
69
|
+
photoHint: 'Fotoğraflı maddeye tıklayarak fotoğrafı indirebilirsiniz.',
|
|
70
|
+
hasPhoto: 'Var',
|
|
71
|
+
yes: 'Evet',
|
|
72
|
+
downloadFailed: 'Dosya indirilemedi.',
|
|
73
|
+
printFailed: 'Rapor açılamadı.',
|
|
74
|
+
},
|
|
75
|
+
en: {
|
|
76
|
+
title: {{nameEnJs}},
|
|
77
|
+
waiting: 'Waiting for the session from the Portal…',
|
|
78
|
+
networkError: 'Request could not be sent (network error).',
|
|
79
|
+
requestFailed: 'The action could not be completed.',
|
|
80
|
+
readOnly: 'You are in a Delegation or View as User session: you can only view this app.',
|
|
81
|
+
myIntro: 'Audits you have done. Click a draft to continue it; print the report of a completed audit.',
|
|
82
|
+
startTitle: 'New audit',
|
|
83
|
+
startSubmit: 'Start audit',
|
|
84
|
+
checklist: 'Checklist',
|
|
85
|
+
workplace: 'Workplace',
|
|
86
|
+
workplaceHelp: 'If it is not in the list, type the location name below.',
|
|
87
|
+
locationName: 'Location name',
|
|
88
|
+
noChecklist: 'There is no checklist in use. Ask your manager to define one.',
|
|
89
|
+
started: 'Audit started; fill in the items.',
|
|
90
|
+
myTable: 'My audits',
|
|
91
|
+
search: 'Search',
|
|
92
|
+
managersOnly: 'Only managers can see this section.',
|
|
93
|
+
dashSummary: '{n} audits completed in the last 30 days; average score {avg}. Failed: {failed}, with a failed critical item: {critical}. Drafts waiting: {drafts}.',
|
|
94
|
+
noAverage: '-',
|
|
95
|
+
chartTitle: 'Score by location',
|
|
96
|
+
seriesLast: 'Latest score',
|
|
97
|
+
seriesAverage: 'Average',
|
|
98
|
+
recentTitle: 'Recent audits',
|
|
99
|
+
allTitle: 'All audits',
|
|
100
|
+
printList: 'Print list',
|
|
101
|
+
listsIntro: 'Checklists used in audits. Click a checklist to edit its items. Changing items does not affect audits already started.',
|
|
102
|
+
listsTable: 'Checklists',
|
|
103
|
+
listForm: 'Checklist details',
|
|
104
|
+
newList: 'New checklist',
|
|
105
|
+
listSaved: 'Checklist saved.',
|
|
106
|
+
itemsTitle: 'Items',
|
|
107
|
+
itemsHint: 'Weight is a whole number from {min} to {max}. If a critical item is non-compliant, the audit fails.',
|
|
108
|
+
newItem: 'New item',
|
|
109
|
+
deleteItem: 'Delete item',
|
|
110
|
+
deleteItemConfirm: 'Delete the item "{title}"? Audits already started are not affected.',
|
|
111
|
+
itemSaved: 'Item saved.',
|
|
112
|
+
itemDeleted: 'Item deleted.',
|
|
113
|
+
auditTitle: 'Audit: {location}',
|
|
114
|
+
auditor: 'Auditor',
|
|
115
|
+
started_at: 'Started',
|
|
116
|
+
editIntro: 'Assess each item. "Not applicable" items are not scored; for a "non-compliant" item, describe what you saw. Once completed, the audit cannot be changed.',
|
|
117
|
+
saveDraft: 'Save draft',
|
|
118
|
+
saved: 'Draft saved.',
|
|
119
|
+
submitAudit: 'Complete audit',
|
|
120
|
+
submitConfirm: 'Complete the audit? Answers cannot be changed afterwards.',
|
|
121
|
+
submitted: 'Audit completed.',
|
|
122
|
+
deleteDraft: 'Delete draft',
|
|
123
|
+
deleteDraftConfirm: 'Delete this draft audit?',
|
|
124
|
+
draftDeleted: 'Draft deleted.',
|
|
125
|
+
printAudit: 'Print report',
|
|
126
|
+
close: 'Close',
|
|
127
|
+
critical: 'critical',
|
|
128
|
+
itemHelp: 'Section: {section} - Weight: {weight}',
|
|
129
|
+
note: 'Note',
|
|
130
|
+
photo: 'Photo',
|
|
131
|
+
generalNote: 'General note',
|
|
132
|
+
photoHint: 'Click an item with a photo to download the photo.',
|
|
133
|
+
hasPhoto: 'Yes',
|
|
134
|
+
yes: 'Yes',
|
|
135
|
+
downloadFailed: 'The file could not be downloaded.',
|
|
136
|
+
printFailed: 'The report could not be opened.',
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const MODEL = {
|
|
141
|
+
manage: '{{permissionPrefix}}Manage',
|
|
142
|
+
noteMax: NOTE_MAX,
|
|
143
|
+
weightMin: WEIGHT_MIN,
|
|
144
|
+
weightMax: WEIGHT_MAX,
|
|
145
|
+
status: choices(dataModel, 'audits', 'status'),
|
|
146
|
+
result: choices(dataModel, 'audits', 'result'),
|
|
147
|
+
answer: choices(dataModel, 'audit_answers', 'result'),
|
|
148
|
+
labels: {
|
|
149
|
+
listName: label(dataModel, 'checklists', 'name'),
|
|
150
|
+
listDescription: label(dataModel, 'checklists', 'description'),
|
|
151
|
+
listActive: label(dataModel, 'checklists', 'active'),
|
|
152
|
+
position: label(dataModel, 'checklist_items', 'position'),
|
|
153
|
+
section: label(dataModel, 'checklist_items', 'section'),
|
|
154
|
+
item: label(dataModel, 'checklist_items', 'title'),
|
|
155
|
+
weight: label(dataModel, 'checklist_items', 'weight'),
|
|
156
|
+
critical: label(dataModel, 'checklist_items', 'critical'),
|
|
157
|
+
checklistName: label(dataModel, 'audits', 'checklist_name'),
|
|
158
|
+
location: label(dataModel, 'audits', 'location_name'),
|
|
159
|
+
auditor: label(dataModel, 'audits', 'auditor_name'),
|
|
160
|
+
status: label(dataModel, 'audits', 'status'),
|
|
161
|
+
submittedAt: label(dataModel, 'audits', 'submitted_at'),
|
|
162
|
+
score: label(dataModel, 'audits', 'score'),
|
|
163
|
+
result: label(dataModel, 'audits', 'result'),
|
|
164
|
+
criticalFailed: label(dataModel, 'audits', 'critical_failed'),
|
|
165
|
+
answer: label(dataModel, 'audit_answers', 'result'),
|
|
166
|
+
note: label(dataModel, 'audit_answers', 'note'),
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function renderShell(lang: Lang, theme: Theme, path: string): string {
|
|
171
|
+
const tx = translator(STRINGS, lang)
|
|
172
|
+
const btn = (id: string, key: string, cls = 'one-btn', hidden = false) =>
|
|
173
|
+
`<button type="button" class="${cls}" id="${id}" data-i18n="${key}"${hidden ? ' hidden' : ''}>${escapeHtml(tx(key))}</button>`
|
|
174
|
+
const body = [
|
|
175
|
+
view(
|
|
176
|
+
'/',
|
|
177
|
+
path,
|
|
178
|
+
`${i18n(tx, 'myIntro', 'p', 'class="one-muted"')}
|
|
179
|
+
<section id="startBox" class="one-card">
|
|
180
|
+
<h2 data-i18n="startTitle">${escapeHtml(tx('startTitle'))}</h2>
|
|
181
|
+
${i18n(tx, 'noChecklist', 'p', 'class="one-muted" id="noChecklist" hidden')}
|
|
182
|
+
<one-form id="startForm" no-cancel></one-form>
|
|
183
|
+
</section>
|
|
184
|
+
<one-filter id="myFilter" for="myTable"></one-filter>
|
|
185
|
+
<one-table id="myTable" src="/api/audits" paging="page" export="xlsx csv" clickable caption="${escapeHtml(tx('myTable'))}"></one-table>`,
|
|
186
|
+
),
|
|
187
|
+
view(
|
|
188
|
+
'/dashboard',
|
|
189
|
+
path,
|
|
190
|
+
`${i18n(tx, 'managersOnly', 'p', 'class="one-muted" id="dashDenied"')}
|
|
191
|
+
<div id="dashArea" hidden>
|
|
192
|
+
<p><strong id="dashSummary"></strong></p>
|
|
193
|
+
<one-chart id="locationChart" type="bar"></one-chart>
|
|
194
|
+
<h2 data-i18n="recentTitle">${escapeHtml(tx('recentTitle'))}</h2>
|
|
195
|
+
<one-table id="recentTable" no-search clickable caption="${escapeHtml(tx('recentTitle'))}"></one-table>
|
|
196
|
+
<h2 data-i18n="allTitle">${escapeHtml(tx('allTitle'))}</h2>
|
|
197
|
+
<one-filter id="allFilter" for="allTable"></one-filter>
|
|
198
|
+
<div class="app-toolbar">${btn('printList', 'printList')}</div>
|
|
199
|
+
<one-table id="allTable" src="/api/all/audits" paging="page" export="xlsx csv" clickable caption="${escapeHtml(tx('allTitle'))}"></one-table>
|
|
200
|
+
</div>`,
|
|
201
|
+
),
|
|
202
|
+
view(
|
|
203
|
+
'/checklists',
|
|
204
|
+
path,
|
|
205
|
+
`${i18n(tx, 'managersOnly', 'p', 'class="one-muted" id="listsDenied"')}
|
|
206
|
+
<div id="listsArea" hidden>
|
|
207
|
+
${i18n(tx, 'listsIntro', 'p', 'class="one-muted"')}
|
|
208
|
+
<one-table id="listsTable" src="/api/checklists" paging="page" clickable caption="${escapeHtml(tx('listsTable'))}"></one-table>
|
|
209
|
+
<section class="one-card">
|
|
210
|
+
<h2 data-i18n="listForm">${escapeHtml(tx('listForm'))}</h2>
|
|
211
|
+
<div class="app-toolbar">${btn('newList', 'newList')}</div>
|
|
212
|
+
<one-form id="listForm" action="/api/checklists" method="POST"></one-form>
|
|
213
|
+
</section>
|
|
214
|
+
<section id="itemsBox" class="one-card" hidden>
|
|
215
|
+
<h2 id="itemsTitle">${escapeHtml(tx('itemsTitle'))}</h2>
|
|
216
|
+
<p class="one-muted" id="itemsHint"></p>
|
|
217
|
+
<one-table id="itemsTable" no-search clickable caption="${escapeHtml(tx('itemsTitle'))}"></one-table>
|
|
218
|
+
<div class="app-toolbar">${btn('newItem', 'newItem')}${btn('deleteItem', 'deleteItem', 'one-btn one-btn-danger', true)}</div>
|
|
219
|
+
<one-form id="itemForm" no-cancel></one-form>
|
|
220
|
+
</section>
|
|
221
|
+
</div>`,
|
|
222
|
+
),
|
|
223
|
+
`<section id="auditPanel" class="one-card app-detail" hidden aria-labelledby="auditTitle">
|
|
224
|
+
<h2 id="auditTitle"></h2>
|
|
225
|
+
<dl id="auditFields"></dl>
|
|
226
|
+
<div id="editBox" hidden>
|
|
227
|
+
${i18n(tx, 'editIntro', 'p', 'class="one-muted"')}
|
|
228
|
+
<one-form id="answersForm" no-cancel></one-form>
|
|
229
|
+
<div class="app-toolbar">${btn('submitAudit', 'submitAudit', 'one-btn one-btn-primary')}${btn('deleteDraft', 'deleteDraft', 'one-btn one-btn-danger')}</div>
|
|
230
|
+
</div>
|
|
231
|
+
<div id="resultBox" hidden>
|
|
232
|
+
<one-table id="answersTable" no-search clickable caption="${escapeHtml(tx('itemsTitle'))}"></one-table>
|
|
233
|
+
${i18n(tx, 'photoHint', 'p', 'class="one-muted"')}
|
|
234
|
+
</div>
|
|
235
|
+
<div class="app-toolbar">${btn('printAudit', 'printAudit')}${btn('closeAudit', 'close', 'one-btn one-btn-text')}</div>
|
|
236
|
+
</section>`,
|
|
237
|
+
].join('\n')
|
|
238
|
+
return renderPage({ lang, theme, title: tx('title'), body, style: '.app-print-frame{position:absolute;width:0;height:0;border:0}' })
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function renderShellScript(navigation: readonly OneNavigationItem[], options: { actingWrites?: boolean } = {}): string {
|
|
242
|
+
return renderClientScript({ strings: STRINGS, navigation, ...(options.actingWrites !== undefined ? { actingWrites: options.actingWrites } : {}), body: pageScript() })
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function pageScript(): string {
|
|
246
|
+
return `
|
|
247
|
+
var M = ${JSON.stringify(MODEL).replace(/<\//g, '<\\/')};
|
|
248
|
+
var startForm = $('startForm'), myTable = $('myTable'), recentTable = $('recentTable'), allTable = $('allTable'), chart = $('locationChart');
|
|
249
|
+
var listsTable = $('listsTable'), listForm = $('listForm'), itemsTable = $('itemsTable'), itemForm = $('itemForm');
|
|
250
|
+
var answersForm = $('answersForm'), answersTable = $('answersTable');
|
|
251
|
+
var current = null, currentAnswers = [], selectedList = null, editingItem = null;
|
|
252
|
+
var workplaceOptions = [], checklistOptions = [], workplacesAvailable = false, optionsLoaded = false;
|
|
253
|
+
|
|
254
|
+
function both(key) { return { tr: S.tr[key], en: S.en[key] }; }
|
|
255
|
+
function choiceText(options, value) { for (var i = 0; i < options.length; i++) if (options[i].value === value) return L(options[i].label); return value || ''; }
|
|
256
|
+
function fail(r) { one.toast({ severity: 'error', summary: t('requestFailed'), detail: problem(r) }); }
|
|
257
|
+
function auditColumns(withAuditor) {
|
|
258
|
+
var cols = [
|
|
259
|
+
{ key: 'location_name', label: M.labels.location },
|
|
260
|
+
{ key: 'checklist_name', label: M.labels.checklistName },
|
|
261
|
+
{ key: 'status', label: M.labels.status, type: 'choice', options: M.status },
|
|
262
|
+
{ key: 'submitted_at', label: M.labels.submittedAt, type: 'datetime' },
|
|
263
|
+
{ key: 'score', label: M.labels.score, type: 'number' },
|
|
264
|
+
{ key: 'result', label: M.labels.result, type: 'choice', options: M.result },
|
|
265
|
+
{ key: 'critical_failed', label: M.labels.criticalFailed, type: 'boolean' }
|
|
266
|
+
];
|
|
267
|
+
if (withAuditor) cols.splice(2, 0, { key: 'auditor_name', label: M.labels.auditor });
|
|
268
|
+
return cols;
|
|
269
|
+
}
|
|
270
|
+
var auditFilter = [
|
|
271
|
+
{ key: 'q', label: both('search'), type: 'text' },
|
|
272
|
+
{ key: 'status', label: M.labels.status, type: 'choice', options: M.status },
|
|
273
|
+
{ key: 'result', label: M.labels.result, type: 'choice', options: M.result },
|
|
274
|
+
{ key: 'submitted_at', label: M.labels.submittedAt, type: 'dateRange' }
|
|
275
|
+
];
|
|
276
|
+
myTable.columns = auditColumns(false);
|
|
277
|
+
$('myFilter').fields = auditFilter;
|
|
278
|
+
allTable.columns = auditColumns(true);
|
|
279
|
+
$('allFilter').fields = auditFilter;
|
|
280
|
+
recentTable.columns = [
|
|
281
|
+
{ key: 'submitted_at', label: M.labels.submittedAt, type: 'datetime' },
|
|
282
|
+
{ key: 'location_name', label: M.labels.location },
|
|
283
|
+
{ key: 'checklist_name', label: M.labels.checklistName },
|
|
284
|
+
{ key: 'auditor_name', label: M.labels.auditor },
|
|
285
|
+
{ key: 'score', label: M.labels.score, type: 'number' },
|
|
286
|
+
{ key: 'result', label: M.labels.result, type: 'choice', options: M.result },
|
|
287
|
+
{ key: 'critical_failed', label: M.labels.criticalFailed, type: 'boolean' }
|
|
288
|
+
];
|
|
289
|
+
answersTable.columns = [
|
|
290
|
+
{ key: 'position', label: M.labels.position, type: 'number' },
|
|
291
|
+
{ key: 'section', label: M.labels.section },
|
|
292
|
+
{ key: 'title', label: M.labels.item },
|
|
293
|
+
{ key: 'critical', label: M.labels.critical, type: 'boolean' },
|
|
294
|
+
{ key: 'result', label: M.labels.answer, type: 'choice', options: M.answer },
|
|
295
|
+
{ key: 'note', label: M.labels.note },
|
|
296
|
+
{ key: 'photo', label: both('photo'), sortable: false, format: function (v) { return v ? t('hasPhoto') : ''; } }
|
|
297
|
+
];
|
|
298
|
+
|
|
299
|
+
// ── Yeni denetim ──
|
|
300
|
+
function startFields() {
|
|
301
|
+
var fields = [{ key: 'checklist_id', label: both('checklist'), type: 'choice', options: checklistOptions, required: true }];
|
|
302
|
+
if (workplacesAvailable && workplaceOptions.length) fields.push({ key: 'location_id', label: both('workplace'), type: 'choice', options: workplaceOptions, help: both('workplaceHelp') });
|
|
303
|
+
fields.push({ key: 'location_name', label: both('locationName'), maxLength: 120 });
|
|
304
|
+
startForm.fields = fields;
|
|
305
|
+
startForm.submitLabel = both('startSubmit');
|
|
306
|
+
$('noChecklist').toggleAttribute('hidden', !optionsLoaded || checklistOptions.length > 0);
|
|
307
|
+
startForm.toggleAttribute('hidden', !optionsLoaded || checklistOptions.length === 0 || !canWrite());
|
|
308
|
+
}
|
|
309
|
+
function loadStartOptions() {
|
|
310
|
+
return Promise.all([
|
|
311
|
+
loadAll('/api/checklists?active=true&_sort=name'),
|
|
312
|
+
api('GET', '/api/workplaces')
|
|
313
|
+
]).then(function (res) {
|
|
314
|
+
// Okunamayan liste "kullanımda liste yok" sayılmaz: hata gösterilir, form ve not önceki hâlinde kalır.
|
|
315
|
+
if (!res[0].ok) { fail(res[0]); return; }
|
|
316
|
+
checklistOptions = res[0].body.items.map(function (x) { return { value: x.id, label: x.name }; });
|
|
317
|
+
workplacesAvailable = !!(res[1].ok && res[1].body.available);
|
|
318
|
+
workplaceOptions = workplacesAvailable ? res[1].body.items.map(function (w) { return { value: w.id, label: w.label }; }) : [];
|
|
319
|
+
optionsLoaded = true;
|
|
320
|
+
startFields();
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
startForm.addEventListener('save', function (e) {
|
|
324
|
+
e.preventDefault();
|
|
325
|
+
var v = e.detail.value, body = { checklist_id: v.checklist_id };
|
|
326
|
+
if (v.location_id) body.location_id = v.location_id; else body.location_name = v.location_name || '';
|
|
327
|
+
api('POST', '/api/audits', body).then(function (r) {
|
|
328
|
+
if (!r.ok) { if (r.body && r.body.errors) startForm.setErrors(r.body.errors, problem(r)); else fail(r); return; }
|
|
329
|
+
one.toast({ severity: 'success', summary: t('started') });
|
|
330
|
+
startForm.value = {};
|
|
331
|
+
myTable.reload();
|
|
332
|
+
showAudit(r.body.audit, r.body.answers, true);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// ── Denetim paneli ──
|
|
337
|
+
function base() { return '/api/audits/' + encodeURIComponent(current.id); }
|
|
338
|
+
function row(dl, labelText, value) { if (value == null || value === '') return; dl.appendChild(el('dt', { text: labelText })); dl.appendChild(el('dd', { text: String(value) })); }
|
|
339
|
+
function answerFields(answers) {
|
|
340
|
+
var fields = [];
|
|
341
|
+
answers.forEach(function (a, i) {
|
|
342
|
+
var head = (i + 1) + '. ' + a.title + (a.critical ? ' (' + t('critical') + ')' : '');
|
|
343
|
+
fields.push({ key: 'r_' + a.id, label: head, type: 'choice', options: M.answer, help: t('itemHelp', { section: a.section || '-', weight: a.weight }) });
|
|
344
|
+
fields.push({ key: 'n_' + a.id, label: both('note'), maxLength: M.noteMax });
|
|
345
|
+
fields.push({ key: 'p_' + a.id, label: both('photo'), type: 'file', accept: 'image/*', maxSize: 5242880, action: '/api/files' });
|
|
346
|
+
});
|
|
347
|
+
fields.push({ key: 'general_note', label: both('generalNote'), type: 'longText', maxLength: 2000 });
|
|
348
|
+
return fields;
|
|
349
|
+
}
|
|
350
|
+
function answerValue(audit, answers) {
|
|
351
|
+
var v = { general_note: audit.general_note || '' };
|
|
352
|
+
answers.forEach(function (a) {
|
|
353
|
+
v['r_' + a.id] = a.result || '';
|
|
354
|
+
v['n_' + a.id] = a.note || '';
|
|
355
|
+
v['p_' + a.id] = a.photo ? { key: a.photo, name: a.photo_name || '' } : null;
|
|
356
|
+
});
|
|
357
|
+
return v;
|
|
358
|
+
}
|
|
359
|
+
function showAudit(audit, answers, editable) {
|
|
360
|
+
current = audit; currentAnswers = answers;
|
|
361
|
+
$('auditTitle').textContent = t('auditTitle', { location: audit.location_name });
|
|
362
|
+
var dl = $('auditFields'); dl.textContent = '';
|
|
363
|
+
row(dl, L(M.labels.checklistName), audit.checklist_name);
|
|
364
|
+
row(dl, t('auditor'), audit.auditor_name);
|
|
365
|
+
row(dl, L(M.labels.status), choiceText(M.status, audit.status));
|
|
366
|
+
row(dl, t('started_at'), fmtDateTime(audit.created_at));
|
|
367
|
+
row(dl, L(M.labels.submittedAt), fmtDateTime(audit.submitted_at));
|
|
368
|
+
if (audit.score != null) row(dl, L(M.labels.score), fmtNumber(audit.score) + ' - ' + choiceText(M.result, audit.result));
|
|
369
|
+
if (audit.critical_failed === true || audit.critical_failed === 1) row(dl, L(M.labels.criticalFailed), t('yes'));
|
|
370
|
+
row(dl, t('generalNote'), audit.status === 'completed' ? audit.general_note : '');
|
|
371
|
+
var edit = editable && canWrite();
|
|
372
|
+
$('editBox').toggleAttribute('hidden', !edit);
|
|
373
|
+
$('resultBox').toggleAttribute('hidden', edit);
|
|
374
|
+
if (edit) {
|
|
375
|
+
answersForm.fields = answerFields(answers);
|
|
376
|
+
answersForm.submitLabel = both('saveDraft');
|
|
377
|
+
answersForm.value = answerValue(audit, answers);
|
|
378
|
+
} else {
|
|
379
|
+
answersTable.rows = answers;
|
|
380
|
+
}
|
|
381
|
+
$('auditPanel').removeAttribute('hidden');
|
|
382
|
+
one.setTitle(audit.location_name);
|
|
383
|
+
}
|
|
384
|
+
function hideAudit() { $('auditPanel').setAttribute('hidden', ''); current = null; one.setTitle(null); }
|
|
385
|
+
function openAudit(id) {
|
|
386
|
+
api('GET', '/api/audits/' + encodeURIComponent(id) + '/answers').then(function (r) {
|
|
387
|
+
if (!r.ok) { fail(r); return; }
|
|
388
|
+
showAudit(r.body.audit, r.body.answers, r.body.editable === true);
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
function answersBody(v) {
|
|
392
|
+
return {
|
|
393
|
+
general_note: v.general_note || '',
|
|
394
|
+
answers: currentAnswers.map(function (a) {
|
|
395
|
+
var p = v['p_' + a.id];
|
|
396
|
+
return { id: a.id, result: v['r_' + a.id] || null, note: v['n_' + a.id] || '', photo: p && p.key ? p : null };
|
|
397
|
+
})
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function saveAnswers() { return api('PUT', base() + '/answers', answersBody(answersForm.value)); }
|
|
401
|
+
answersForm.addEventListener('save', function (e) {
|
|
402
|
+
e.preventDefault();
|
|
403
|
+
saveAnswers().then(function (r) {
|
|
404
|
+
if (!r.ok) { if (r.body && r.body.errors) answersForm.setErrors(r.body.errors, problem(r)); else fail(r); return; }
|
|
405
|
+
one.toast({ severity: 'success', summary: t('saved') });
|
|
406
|
+
showAudit(r.body.audit, r.body.answers, r.body.editable === true);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
$('submitAudit').addEventListener('click', function () {
|
|
410
|
+
if (!current) return;
|
|
411
|
+
one.confirm({ title: t('submitAudit'), message: t('submitConfirm'), acceptLabel: t('submitAudit') }).then(function (ok) {
|
|
412
|
+
if (!ok) return;
|
|
413
|
+
return saveAnswers().then(function (r) {
|
|
414
|
+
if (!r.ok) { fail(r); return; }
|
|
415
|
+
return api('POST', base() + '/submit').then(function (s) {
|
|
416
|
+
if (!s.ok) {
|
|
417
|
+
var detail = problem(s);
|
|
418
|
+
if (s.body && s.body.errors) detail = s.body.errors.map(function (x) { return x.message; }).join(' ');
|
|
419
|
+
one.toast({ severity: 'error', summary: t('requestFailed'), detail: detail });
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
one.toast({ severity: 'success', summary: t('submitted') });
|
|
423
|
+
myTable.reload();
|
|
424
|
+
openAudit(current.id);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
$('deleteDraft').addEventListener('click', function () {
|
|
430
|
+
if (!current) return;
|
|
431
|
+
one.confirm({ title: t('deleteDraft'), message: t('deleteDraftConfirm'), severity: 'danger', acceptLabel: t('deleteDraft') }).then(function (ok) {
|
|
432
|
+
if (!ok) return;
|
|
433
|
+
return api('DELETE', base()).then(function (r) { if (toastResult(r, 'draftDeleted')) { hideAudit(); myTable.reload(); } });
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
function printPath(path) {
|
|
437
|
+
one.fetch(path + (path.indexOf('?') >= 0 ? '&' : '?') + '_lang=' + lang).then(function (res) {
|
|
438
|
+
if (!res.ok) { one.toast({ severity: 'error', summary: t('printFailed') }); return; }
|
|
439
|
+
return res.text().then(function (html) {
|
|
440
|
+
var frame = document.createElement('iframe');
|
|
441
|
+
frame.className = 'app-print-frame';
|
|
442
|
+
frame.setAttribute('title', t('printAudit'));
|
|
443
|
+
frame.srcdoc = html;
|
|
444
|
+
frame.addEventListener('load', function () { frame.contentWindow.print(); setTimeout(function () { frame.remove(); }, 60000); });
|
|
445
|
+
document.body.appendChild(frame);
|
|
446
|
+
});
|
|
447
|
+
}, function () { one.toast({ severity: 'error', summary: t('printFailed') }); });
|
|
448
|
+
}
|
|
449
|
+
$('printAudit').addEventListener('click', function () { if (current) printPath(base() + '/report.html'); });
|
|
450
|
+
$('closeAudit').addEventListener('click', hideAudit);
|
|
451
|
+
answersTable.addEventListener('rowclick', function (e) {
|
|
452
|
+
var a = e.detail.row;
|
|
453
|
+
if (!current || !a.photo) return;
|
|
454
|
+
one.fetch(base() + '/answers/' + encodeURIComponent(a.id) + '/photo').then(function (res) {
|
|
455
|
+
if (!res.ok) { one.toast({ severity: 'error', summary: t('downloadFailed') }); return; }
|
|
456
|
+
return res.arrayBuffer().then(function (data) { return one.download({ name: a.photo_name || 'fotograf', mime: (res.headers.get('content-type') || 'application/octet-stream').split(';')[0], data: data }); });
|
|
457
|
+
}, function () { one.toast({ severity: 'error', summary: t('downloadFailed') }); });
|
|
458
|
+
});
|
|
459
|
+
myTable.addEventListener('rowclick', function (e) { openAudit(e.detail.row.id); });
|
|
460
|
+
recentTable.addEventListener('rowclick', function (e) { openAudit(e.detail.row.id); });
|
|
461
|
+
allTable.addEventListener('rowclick', function (e) { openAudit(e.detail.row.id); });
|
|
462
|
+
|
|
463
|
+
// ── Pano ──
|
|
464
|
+
function loadDashboard() {
|
|
465
|
+
if (!can(M.manage)) return;
|
|
466
|
+
api('GET', '/api/dashboard').then(function (r) {
|
|
467
|
+
if (!r.ok) { fail(r); return; }
|
|
468
|
+
var s = r.body.summary;
|
|
469
|
+
$('dashSummary').textContent = t('dashSummary', { n: fmtNumber(s.audits), avg: s.average == null ? t('noAverage') : fmtNumber(s.average), failed: fmtNumber(s.failed), critical: fmtNumber(s.criticalFailures), drafts: fmtNumber(s.drafts) });
|
|
470
|
+
chart.label = both('chartTitle');
|
|
471
|
+
chart.data = {
|
|
472
|
+
labels: r.body.locations.map(function (x) { return x.location; }),
|
|
473
|
+
series: [
|
|
474
|
+
{ name: both('seriesLast'), values: r.body.locations.map(function (x) { return x.last_score || 0; }) },
|
|
475
|
+
{ name: both('seriesAverage'), values: r.body.locations.map(function (x) { return x.average || 0; }) }
|
|
476
|
+
]
|
|
477
|
+
};
|
|
478
|
+
recentTable.rows = r.body.recent;
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
$('printList').addEventListener('click', function () {
|
|
482
|
+
var params = ($('allFilter').value && $('allFilter').value.params) || {};
|
|
483
|
+
var qs = [];
|
|
484
|
+
for (var k in params) if (Object.prototype.hasOwnProperty.call(params, k)) qs.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k]));
|
|
485
|
+
printPath('/api/all/audits/report.html' + (qs.length ? '?' + qs.join('&') : ''));
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// ── Kontrol listeleri ──
|
|
489
|
+
listsTable.columns = [
|
|
490
|
+
{ key: 'name', label: M.labels.listName },
|
|
491
|
+
{ key: 'active', label: M.labels.listActive, type: 'boolean' },
|
|
492
|
+
{ key: 'updated_at', label: { tr: 'Güncellenme', en: 'Updated' }, type: 'datetime' }
|
|
493
|
+
];
|
|
494
|
+
listForm.fields = [
|
|
495
|
+
{ key: 'name', label: M.labels.listName, required: true, maxLength: 120 },
|
|
496
|
+
{ key: 'description', label: M.labels.listDescription, type: 'longText', maxLength: 2000 },
|
|
497
|
+
{ key: 'active', label: M.labels.listActive, type: 'boolean' }
|
|
498
|
+
];
|
|
499
|
+
itemsTable.columns = [
|
|
500
|
+
{ key: 'position', label: M.labels.position, type: 'number' },
|
|
501
|
+
{ key: 'section', label: M.labels.section },
|
|
502
|
+
{ key: 'title', label: M.labels.item },
|
|
503
|
+
{ key: 'weight', label: M.labels.weight, type: 'number' },
|
|
504
|
+
{ key: 'critical', label: M.labels.critical, type: 'boolean' }
|
|
505
|
+
];
|
|
506
|
+
itemForm.fields = [
|
|
507
|
+
{ key: 'position', label: M.labels.position, type: 'number', min: 1, max: 999, required: true },
|
|
508
|
+
{ key: 'section', label: M.labels.section, maxLength: 80 },
|
|
509
|
+
{ key: 'title', label: M.labels.item, required: true, maxLength: 200 },
|
|
510
|
+
{ key: 'weight', label: M.labels.weight, type: 'number', min: M.weightMin, max: M.weightMax, required: true },
|
|
511
|
+
{ key: 'critical', label: M.labels.critical, type: 'boolean' }
|
|
512
|
+
];
|
|
513
|
+
function setHint() { $('itemsHint').textContent = t('itemsHint', { min: M.weightMin, max: M.weightMax }); }
|
|
514
|
+
function newList() {
|
|
515
|
+
selectedList = null;
|
|
516
|
+
listForm.setAttribute('action', '/api/checklists'); listForm.setAttribute('method', 'POST');
|
|
517
|
+
listForm.value = { active: true };
|
|
518
|
+
$('itemsBox').setAttribute('hidden', '');
|
|
519
|
+
}
|
|
520
|
+
function nextPosition() { var rows = itemsTable.rows || []; return rows.reduce(function (m, r) { return Math.max(m, Number(r.position) || 0); }, 0) + 1; }
|
|
521
|
+
function newItem() { editingItem = null; itemForm.value = { position: nextPosition(), weight: 1, critical: false }; $('deleteItem').setAttribute('hidden', ''); }
|
|
522
|
+
function loadItems() {
|
|
523
|
+
if (!selectedList) return;
|
|
524
|
+
api('GET', '/api/checklist_items?checklist_id=' + encodeURIComponent(selectedList.id) + '&_sort=position&_size=200').then(function (r) {
|
|
525
|
+
itemsTable.rows = r.ok ? r.body.items : [];
|
|
526
|
+
if (!r.ok) fail(r);
|
|
527
|
+
newItem();
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
function selectList(r) {
|
|
531
|
+
selectedList = r;
|
|
532
|
+
listForm.setAttribute('action', '/api/checklists/' + encodeURIComponent(r.id)); listForm.setAttribute('method', 'PATCH');
|
|
533
|
+
listForm.value = { name: r.name, description: r.description || '', active: r.active };
|
|
534
|
+
$('itemsTitle').textContent = t('itemsTitle') + ': ' + r.name;
|
|
535
|
+
$('itemsBox').removeAttribute('hidden');
|
|
536
|
+
loadItems();
|
|
537
|
+
}
|
|
538
|
+
listsTable.addEventListener('rowclick', function (e) { if (canWrite()) selectList(e.detail.row); });
|
|
539
|
+
$('newList').addEventListener('click', newList);
|
|
540
|
+
listForm.addEventListener('saved', function (e) {
|
|
541
|
+
e.preventDefault();
|
|
542
|
+
one.toast({ severity: 'success', summary: t('listSaved') });
|
|
543
|
+
listsTable.reload(); loadStartOptions();
|
|
544
|
+
if (e.detail.response && e.detail.response.id) selectList(e.detail.response);
|
|
545
|
+
});
|
|
546
|
+
itemsTable.addEventListener('rowclick', function (e) {
|
|
547
|
+
if (!canWrite()) return;
|
|
548
|
+
editingItem = e.detail.row;
|
|
549
|
+
itemForm.value = { position: editingItem.position, section: editingItem.section || '', title: editingItem.title, weight: editingItem.weight, critical: editingItem.critical };
|
|
550
|
+
$('deleteItem').removeAttribute('hidden');
|
|
551
|
+
});
|
|
552
|
+
$('newItem').addEventListener('click', newItem);
|
|
553
|
+
itemForm.addEventListener('save', function (e) {
|
|
554
|
+
e.preventDefault();
|
|
555
|
+
if (!selectedList) return;
|
|
556
|
+
var v = e.detail.value, body = { position: v.position, section: v.section || '', title: v.title, weight: v.weight, critical: v.critical === true };
|
|
557
|
+
var req = editingItem
|
|
558
|
+
? api('PATCH', '/api/checklist_items/' + encodeURIComponent(editingItem.id), body)
|
|
559
|
+
: api('POST', '/api/checklist_items', Object.assign({ checklist_id: selectedList.id }, body));
|
|
560
|
+
req.then(function (r) {
|
|
561
|
+
if (r.ok) { one.toast({ severity: 'success', summary: t('itemSaved') }); loadItems(); return; }
|
|
562
|
+
if (r.body && r.body.errors) itemForm.setErrors(r.body.errors, problem(r)); else fail(r);
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
$('deleteItem').addEventListener('click', function () {
|
|
566
|
+
if (!editingItem) return;
|
|
567
|
+
one.confirm({ title: t('deleteItem'), message: t('deleteItemConfirm', { title: editingItem.title }), severity: 'danger', acceptLabel: t('deleteItem') }).then(function (ok) {
|
|
568
|
+
if (!ok) return;
|
|
569
|
+
return api('DELETE', '/api/checklist_items/' + encodeURIComponent(editingItem.id)).then(function (r) { if (toastResult(r, 'itemDeleted')) loadItems(); });
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
onSession(function () {
|
|
574
|
+
var manager = can(M.manage);
|
|
575
|
+
$('dashArea').toggleAttribute('hidden', !manager); $('dashDenied').toggleAttribute('hidden', manager);
|
|
576
|
+
$('listsArea').toggleAttribute('hidden', !manager); $('listsDenied').toggleAttribute('hidden', manager);
|
|
577
|
+
$('newList').toggleAttribute('hidden', !canWrite());
|
|
578
|
+
if (manager) { newList(); loadDashboard(); }
|
|
579
|
+
});
|
|
580
|
+
onView(function (p) { hideAudit(); if (p === '/dashboard') loadDashboard(); });
|
|
581
|
+
onLang(function () { setHint(); startFields(); });
|
|
582
|
+
setHint();
|
|
583
|
+
onReady(function () { loadStartOptions(); });
|
|
584
|
+
`
|
|
585
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scopes": ["orgschema.read"],
|
|
3
|
+
"services": { "database": true, "files": true, "cache": false },
|
|
4
|
+
"menuIcon": "pi pi-check-square",
|
|
5
|
+
"navigation": [
|
|
6
|
+
{ "path": "/", "label": { "tr": "Denetimlerim", "en": "My audits" } },
|
|
7
|
+
{ "path": "/dashboard", "label": { "tr": "Pano", "en": "Dashboard" }, "permission": "{{permissionPrefix}}Manage" },
|
|
8
|
+
{ "path": "/checklists", "label": { "tr": "Kontrol listeleri", "en": "Checklists" }, "permission": "{{permissionPrefix}}Manage" }
|
|
9
|
+
],
|
|
10
|
+
"permissions": [
|
|
11
|
+
{ "code": "{{permissionPrefix}}Manage", "name": { "tr": "Kontrol listelerini yönet ve bütün denetimleri gör", "en": "Manage checklists and see all audits" } }
|
|
12
|
+
],
|
|
13
|
+
"agent": {
|
|
14
|
+
"summary": {
|
|
15
|
+
"tr": "Saha denetimi uygulaması: mağaza ve şubelerde yapılan denetimler, puanları, sonuçları ve uygun bulunmayan maddeler.",
|
|
16
|
+
"en": "Field audit app: audits of stores and branches, their scores, results and non-compliant items."
|
|
17
|
+
},
|
|
18
|
+
"tools": [
|
|
19
|
+
{
|
|
20
|
+
"name": "recent-audit-results",
|
|
21
|
+
"title": { "tr": "Son denetim sonuçları", "en": "Recent audit results" },
|
|
22
|
+
"description": {
|
|
23
|
+
"tr": "Tamamlanmış son denetimleri yer, kontrol listesi, denetçi, tarih, puan, sonuç ve uygun bulunmayan maddelerle döndürür; yer adıyla süzülebilir. Salt okunur.",
|
|
24
|
+
"en": "Returns the latest completed audits with location, checklist, auditor, date, score, result and non-compliant items; can be filtered by location name. Read-only."
|
|
25
|
+
},
|
|
26
|
+
"readOnly": true,
|
|
27
|
+
"permission": "{{permissionPrefix}}Manage",
|
|
28
|
+
"input": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"location": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Yer adında geçen ifade (ör. mağaza adı)" },
|
|
32
|
+
"limit": { "type": "integer", "minimum": 1, "maximum": 30, "description": "En çok kaç denetim (varsayılan 10)" }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "location-scores",
|
|
38
|
+
"title": { "tr": "Yerlere göre denetim puanları", "en": "Audit scores by location" },
|
|
39
|
+
"description": {
|
|
40
|
+
"tr": "Her denetlenen yer için tamamlanmış denetim sayısını, son puanı, ortalama puanı ve son denetim tarihini döndürür. Salt okunur.",
|
|
41
|
+
"en": "Returns, for each audited location, the number of completed audits, the latest score, the average score and the latest audit date. Read-only."
|
|
42
|
+
},
|
|
43
|
+
"readOnly": true,
|
|
44
|
+
"permission": "{{permissionPrefix}}Manage",
|
|
45
|
+
"input": { "type": "object", "properties": {} }
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
}
|