main
vue 299 lines 8.18 KB
Raw
1 <template>
2 <n-spin :show="loading" class="flex min-h-48 grow flex-col" content-class="flex grow flex-col gap-4">
3 <div>
4 <n-collapse-transition :show="!showUploadForm">
5 <div class="flex flex-wrap items-center gap-3">
6 <n-button v-if="templateNameList.length" type="primary" @click="openUploadForm()">
7 <template #icon>
8 <Icon :name="UploadIcon" />
9 </template>
10 Upload Report Template file
11 </n-button>
12
13 <n-button
14 v-if="!isDefaultTemplatePresent && templateNameList.length"
15 :loading="checkingDefaultTemplate"
16 @click="uploadDefaultTemplate()"
17 >
18 <template #icon>
19 <Icon :name="DefaultTemplateIcon" />
20 </template>
21 Load the SOCFortress Template
22 </n-button>
23 </div>
24 </n-collapse-transition>
25
26 <n-collapse-transition :show="showUploadForm">
27 <div class="flex flex-col gap-2">
28 <n-upload
29 v-model:file-list="fileList"
30 :max="1"
31 :disabled="uploading"
32 accept="application/vnd.openxmlformats-officedocument.wordprocessingml.document, .docx, .DOCX, text/html, .html, .HTML"
33 >
34 <n-upload-dragger>
35 <div>
36 <Icon :name="UploadIcon" :size="28" :depth="3" />
37 </div>
38 <div class="font-semibold">Click or drag a file to this area to upload</div>
39 <p class="mt-2">
40 Only
41 <strong>.docx</strong>
42 and
43 <strong>.html</strong>
44 files are accepted
45 </p>
46 </n-upload-dragger>
47 </n-upload>
48
49 <div class="flex items-center justify-end gap-3">
50 <n-button quaternary :disabled="uploading" @click="closeUploadForm()">Close</n-button>
51
52 <n-button
53 :disabled="!isValid"
54 :loading="uploading"
55 type="primary"
56 @click="uploadCustomTemplate()"
57 >
58 <template #icon>
59 <Icon :name="UploadIcon" />
60 </template>
61
62 Upload
63 </n-button>
64 </div>
65 </div>
66 </n-collapse-transition>
67 </div>
68
69 <div class="flex flex-col gap-2">
70 <template v-if="templateNameList.length">
71 <n-card
72 v-for="templateName of templateNameList"
73 :key="templateName"
74 size="small"
75 class="overflow-hidden"
76 embedded
77 content-class="flex flex-wrap items-center justify-between gap-4"
78 >
79 <div class="flex gap-3">
80 <n-tooltip to="body">
81 <template #trigger>
82 <n-button
83 size="tiny"
84 type="primary"
85 text
86 :loading="downloading === templateName"
87 @click="downloadTemplate(templateName)"
88 >
89 <template #icon>
90 <Icon :name="DownloadIcon" />
91 </template>
92 </n-button>
93 </template>
94 Download
95 </n-tooltip>
96 <span>
97 {{ templateName }}
98 </span>
99 </div>
100
101 <n-popconfirm to="body" @positive-click="deleteTemplate(templateName)">
102 <template #trigger>
103 <n-button quaternary size="tiny">Delete</n-button>
104 </template>
105 Are you sure you want to delete this template?
106 </n-popconfirm>
107 </n-card>
108 </template>
109 <template v-else>
110 <n-collapse-transition :show="!showUploadForm">
111 <n-empty v-if="!loading" class="min-h-48">
112 <div class="flex flex-col items-center gap-4">
113 <p>No templates found</p>
114 <div class="flex flex-wrap items-center gap-3">
115 <n-button type="primary" :loading="uploading" @click="openUploadForm()">
116 <template #icon>
117 <Icon :name="UploadIcon" />
118 </template>
119 Upload a Report Template file
120 </n-button>
121 <n-button :loading="uploading" @click="uploadDefaultTemplate()">
122 <template #icon>
123 <Icon :name="DefaultTemplateIcon" />
124 </template>
125 Load the SOCFortress Template
126 </n-button>
127 </div>
128 </div>
129 </n-empty>
130 </n-collapse-transition>
131 </template>
132 </div>
133 </n-spin>
134 </template>
135
136 <script setup lang="ts">
137 import type { UploadFileInfo } from "naive-ui"
138 import saveAs from "file-saver"
139 import {
140 NButton,
141 NCard,
142 NCollapseTransition,
143 NEmpty,
144 NPopconfirm,
145 NSpin,
146 NTooltip,
147 NUpload,
148 NUploadDragger,
149 useMessage
150 } from "naive-ui"
151 import { computed, onBeforeMount, ref, watch } from "vue"
152 import Api from "@/api"
153 import Icon from "@/components/common/Icon.vue"
154 import { useCaseReportTemplateStore } from "@/stores/caseReportTemplate"
155
156 const UploadIcon = "carbon:cloud-upload"
157 const DownloadIcon = "carbon:document-download"
158 const DefaultTemplateIcon = "carbon:document-sketch"
159 const caseReportTemplateStore = useCaseReportTemplateStore()
160 const message = useMessage()
161 const loadingList = computed(() => caseReportTemplateStore.loading)
162 const uploading = ref(false)
163 const canceling = ref(false)
164 const checkingDefaultTemplate = ref(false)
165 const downloading = ref<false | string>(false)
166 const loading = computed(() => loadingList.value || uploading.value || canceling.value)
167 const showUploadForm = ref(false)
168 const templateNameList = computed(() => caseReportTemplateStore.templatesList)
169 const fileList = ref<UploadFileInfo[]>([])
170 const newFile = computed<File | null>(() => fileList.value?.[0]?.file || null)
171 const isValid = computed(() => !!newFile.value)
172 const isDefaultTemplatePresent = ref(true)
173
174 function openUploadForm() {
175 showUploadForm.value = true
176 }
177
178 function closeUploadForm() {
179 showUploadForm.value = false
180 }
181
182 function uploadCustomTemplate() {
183 if (!newFile.value) return
184
185 uploading.value = true
186
187 caseReportTemplateStore
188 .uploadCustomTemplate(newFile.value)
189 .then(res => {
190 if (res.data.success) {
191 message.success(res.data?.message || "Case Report Template uploaded successfully")
192 fileList.value = []
193 } else {
194 message.warning(res.data?.message || "An error occurred. Please try again later.")
195 }
196 })
197 .catch(err => {
198 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
199 })
200 .finally(() => {
201 uploading.value = false
202 })
203 }
204
205 function uploadDefaultTemplate() {
206 uploading.value = true
207
208 Api.incidentManagement.cases
209 .uploadDefaultCaseReportTemplate()
210 .then(res => {
211 if (res.data.success) {
212 message.success(res.data?.message || "Case Report Template uploaded successfully")
213 refreshTemplates()
214 } else {
215 message.warning(res.data?.message || "An error occurred. Please try again later.")
216 }
217 })
218 .catch(err => {
219 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
220 })
221 .finally(() => {
222 uploading.value = false
223 })
224 }
225
226 function checkDefaultCaseReportTemplateExists() {
227 checkingDefaultTemplate.value = true
228
229 Api.incidentManagement.cases
230 .checkDefaultCaseReportTemplateExists()
231 .then(res => {
232 if (res.data.success) {
233 isDefaultTemplatePresent.value = res.data.default_template_exists
234 } else {
235 message.warning(res.data?.message || "An error occurred. Please try again later.")
236 }
237 })
238 .catch(err => {
239 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
240 })
241 .finally(() => {
242 checkingDefaultTemplate.value = false
243 })
244 }
245
246 function downloadTemplate(templateName: string) {
247 downloading.value = templateName
248
249 Api.incidentManagement.cases
250 .downloadCaseReportTemplate(templateName)
251 .then(res => {
252 if (res.data) {
253 saveAs(res.data, templateName)
254 } else {
255 message.warning("An error occurred. Please try again later.")
256 }
257 })
258 .catch(err => {
259 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
260 })
261 .finally(() => {
262 downloading.value = false
263 })
264 }
265
266 function deleteTemplate(templateName: string) {
267 canceling.value = true
268
269 caseReportTemplateStore
270 .deleteTemplate(templateName)
271 .then(res => {
272 if (res.data.success) {
273 message.success(res.data?.message || "Case Report Template deleted successfully")
274 } else {
275 message.warning(res.data?.message || "An error occurred. Please try again later.")
276 }
277 })
278 .catch(err => {
279 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
280 })
281 .finally(() => {
282 canceling.value = false
283 })
284 }
285
286 function refreshTemplates() {
287 caseReportTemplateStore.refreshTemplates().catch(err => {
288 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
289 })
290 }
291
292 watch(templateNameList, () => {
293 checkDefaultCaseReportTemplateExists()
294 })
295
296 onBeforeMount(() => {
297 refreshTemplates()
298 })
299 </script>