main
vue 201 lines 5.41 KB
Raw
1 <template>
2 <n-spin :show="loading" class="flex grow flex-col" content-class="flex grow flex-col">
3 <div class="flex grow flex-col justify-between gap-4">
4 <div class="content-box flex flex-col gap-4 px-6 py-3">
5 <div class="flex flex-col gap-4 sm:flex-row!">
6 <CardKV
7 :color="
8 caseData.case_status === 'OPEN'
9 ? 'danger'
10 : caseData.case_status === 'IN_PROGRESS'
11 ? 'warning'
12 : caseData.case_status === 'CLOSED'
13 ? 'success'
14 : undefined
15 "
16 size="lg"
17 class="w-full grow"
18 >
19 <template #key>
20 <div class="flex items-center gap-2">
21 <StatusIcon :status="caseData.case_status" />
22 <span>Status</span>
23 </div>
24 </template>
25 <template #value>
26 <div class="flex">
27 <CaseStatusSwitch
28 v-slot="{ loading: loadingStatus }"
29 :case-data
30 @updated="updateCase($event)"
31 >
32 <div
33 class="flex items-center gap-3"
34 :class="{
35 'cursor-not-allowed': loadingStatus,
36 'cursor-pointer': !loadingStatus
37 }"
38 >
39 <span>{{ caseData.case_status || "n/d" }}</span>
40 <n-spin
41 :size="14"
42 :show="loadingStatus"
43 content-class="flex flex-col justify-center"
44 >
45 <Icon :name="EditIcon" />
46 </n-spin>
47 </div>
48 </CaseStatusSwitch>
49 </div>
50 </template>
51 </CardKV>
52
53 <CardKV :color="caseData.assigned_to ? 'success' : undefined" size="lg" class="w-full grow">
54 <template #key>
55 <div class="flex items-center gap-2">
56 <AssigneeIcon :assignee="caseData.assigned_to" />
57 <span>Assigned to</span>
58 </div>
59 </template>
60 <template #value>
61 <div class="flex">
62 <CaseAssignUser
63 v-slot="{ loading: loadingAssignee }"
64 :case-data
65 @updated="updateCase($event)"
66 >
67 <div
68 class="flex items-center gap-3"
69 :class="{
70 'cursor-not-allowed': loadingAssignee,
71 'cursor-pointer': !loadingAssignee
72 }"
73 >
74 <span>{{ caseData.assigned_to || "n/d" }}</span>
75 <n-spin
76 :size="14"
77 :show="loadingAssignee"
78 content-class="flex flex-col justify-center"
79 >
80 <Icon :name="EditIcon" />
81 </n-spin>
82 </div>
83 </CaseAssignUser>
84 </div>
85 </template>
86 </CardKV>
87 </div>
88
89 <CardKV>
90 <template #key>description</template>
91 <template #value>
92 <span class="whitespace-pre-wrap">
93 {{ caseData.case_description ?? "-" }}
94 </span>
95 </template>
96 </CardKV>
97
98 <div class="grid-auto-fit-250 grid gap-2">
99 <CardKV>
100 <template #key>id</template>
101 <template #value>#{{ caseData.id }}</template>
102 </CardKV>
103
104 <CardKV>
105 <template #key>creation time</template>
106 <template #value>
107 {{
108 caseData.case_creation_time
109 ? formatDate(caseData.case_creation_time, dFormats.datetime)
110 : "-"
111 }}
112 </template>
113 </CardKV>
114
115 <CardKV>
116 <template #key>customer code</template>
117 <template #value>
118 <code
119 v-if="caseData.customer_code"
120 class="text-primary cursor-pointer"
121 @click="routeCustomer({ code: caseData.customer_code }).navigate()"
122 >
123 {{ caseData.customer_code }}
124 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
125 </code>
126 <span v-else>-</span>
127 </template>
128 </CardKV>
129 </div>
130 </div>
131
132 <div class="bg-secondary border-default flex justify-end gap-3 border-t px-6 py-4">
133 <n-button type="error" secondary @click="handleDelete()">
134 <template #icon>
135 <Icon :name="TrashIcon" />
136 </template>
137 Delete
138 </n-button>
139 <CaseReportButton :case-id="caseData.id" />
140 </div>
141 </div>
142 </n-spin>
143 </template>
144
145 <script setup lang="ts">
146 import type { Case } from "@/types/incidentManagement/cases.d"
147 import { NButton, NSpin, useDialog, useMessage } from "naive-ui"
148 import { ref, toRefs } from "vue"
149 import CardKV from "@/components/common/cards/CardKV.vue"
150 import Icon from "@/components/common/Icon.vue"
151 import { useNavigation } from "@/composables/useNavigation"
152 import { useSettingsStore } from "@/stores/settings"
153 import { formatDate } from "@/utils/format"
154 import AssigneeIcon from "../common/AssigneeIcon.vue"
155 import StatusIcon from "../common/StatusIcon.vue"
156 import CaseAssignUser from "./CaseAssignUser.vue"
157 import CaseReportButton from "./CaseReportButton.vue"
158 import CaseStatusSwitch from "./CaseStatusSwitch.vue"
159 import { handleDeleteCase } from "./utils"
160
161 const props = defineProps<{ caseData: Case }>()
162 const emit = defineEmits<{
163 (e: "deleted"): void
164 (e: "updated", value: Case): void
165 }>()
166
167 const { caseData } = toRefs(props)
168
169 const TrashIcon = "carbon:trash-can"
170 const LinkIcon = "carbon:launch"
171 const EditIcon = "uil:edit-alt"
172
173 const { routeCustomer } = useNavigation()
174 const dialog = useDialog()
175 const message = useMessage()
176 const dFormats = useSettingsStore().dateFormat
177 const loading = ref(false)
178
179 function updateCase(updatedAlert: Case) {
180 emit("updated", updatedAlert)
181 }
182
183 function handleDelete() {
184 if (caseData.value) {
185 handleDeleteCase({
186 caseData: caseData.value,
187 cbBefore: () => {
188 loading.value = true
189 },
190 cbSuccess: () => {
191 emit("deleted")
192 },
193 cbAfter: () => {
194 loading.value = false
195 },
196 message,
197 dialog
198 })
199 }
200 }
201 </script>