57 lines
3.9 KiB
Vue
57 lines
3.9 KiB
Vue
<script setup lang="ts">
|
|
import { inject } from 'vue'
|
|
import type { KbxWorkItem, KbxWorkItemAction } from '@kbx/contracts'
|
|
import { KbxPermissionHostKey } from '../permission/host'
|
|
import KbxButton from './KbxButton.vue'
|
|
import KbxDrawer from './KbxDrawer.vue'
|
|
|
|
const props = defineProps<{ item: KbxWorkItem | null; can?: (permission: string) => boolean }>()
|
|
const emit = defineEmits<{ close: []; action: [KbxWorkItemAction] }>()
|
|
const permissionHost=inject(KbxPermissionHostKey,null)
|
|
function canPermission(permission:string){return props.can?props.can(permission):(permissionHost?.has(permission)??false)}
|
|
function allowed(action:KbxWorkItemAction){return !action.permission||canPermission(action.permission)}
|
|
function visible(action:KbxWorkItemAction){return allowed(action)||action.permissionMode==='disable'}
|
|
function invoke(action:KbxWorkItemAction){if(allowed(action))emit('action',action)}
|
|
</script>
|
|
|
|
<template>
|
|
<KbxDrawer :open="Boolean(item)" :title="item?.title ?? '예외 상세'" @update:open="value=>{if(!value)emit('close')}">
|
|
<article v-if="item" class="kbx-exception-detail" data-kbx-component="exception-detail-drawer" :data-severity="item.severity">
|
|
<header class="kbx-exception-detail__status">
|
|
<span>{{item.code}}</span><strong>{{item.status==='resolved'?'해결':item.status==='claimed'?'처리중':item.status==='ignored'?'제외':'확인 필요'}}</strong>
|
|
</header>
|
|
<section class="meta" aria-label="예외 정보">
|
|
<dl>
|
|
<div><dt>모듈</dt><dd>{{ item.sourceModule }}</dd></div>
|
|
<div><dt>대상</dt><dd>{{ item.sourceType }} · {{ item.referenceNo }}</dd></div>
|
|
<div><dt>발생</dt><dd>{{ item.occurredAt }}</dd></div>
|
|
<div><dt>담당</dt><dd>{{ item.ownerName || '미지정' }}</dd></div>
|
|
<div v-if="item.dueAt"><dt>기한</dt><dd>{{item.dueAt}}</dd></div>
|
|
</dl>
|
|
</section>
|
|
<section class="detail">
|
|
<h2>원인/안내</h2>
|
|
<p>{{ item.detail || '추가 설명이 없습니다.' }}</p>
|
|
<slot name="context" :item="item" />
|
|
</section>
|
|
</article>
|
|
<template #footer>
|
|
<div v-if="item" class="kbx-exception-detail__actions" role="toolbar" aria-label="예외 후속 작업">
|
|
<KbxButton
|
|
v-for="action in (item.actions ?? []).filter(visible)"
|
|
:key="action.id"
|
|
:label="action.label"
|
|
:variant="action.danger?'danger':'secondary'"
|
|
:disabled="!allowed(action)"
|
|
:title="!allowed(action)?'이 작업을 실행할 권한이 없습니다.':undefined"
|
|
@click="invoke(action)"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</KbxDrawer>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.kbx-exception-detail{display:grid;gap:var(--kbx-space-4)}.kbx-exception-detail__status{display:flex;align-items:center;justify-content:space-between;gap:var(--kbx-space-2);padding:var(--kbx-space-2) var(--kbx-space-3);border:var(--kbx-border-width) solid var(--kbx-color-border);background:var(--kbx-color-surface-muted)}.kbx-exception-detail[data-severity="warning"] .kbx-exception-detail__status{border-color:var(--kbx-color-warning-border);background:var(--kbx-color-warning-surface)}.kbx-exception-detail[data-severity="critical"] .kbx-exception-detail__status{border-color:var(--kbx-color-danger-border);background:var(--kbx-color-danger-surface)}.kbx-exception-detail__status span{color:var(--kbx-color-text-muted);font-size:var(--kbx-font-xs)}.meta,.detail{padding-bottom:var(--kbx-space-4);border-bottom:var(--kbx-border-width) solid var(--kbx-color-border)}dl{margin:0;display:grid;gap:var(--kbx-space-2)}dl div{display:grid;grid-template-columns:var(--kbx-label-width) 1fr;gap:var(--kbx-space-2)}dt{color:var(--kbx-color-text-muted)}dd{margin:0}h2{margin:0 0 var(--kbx-space-2);font-size:var(--kbx-font-md)}p{margin:0;line-height:1.6}.kbx-exception-detail__actions{display:flex;justify-content:flex-end;gap:var(--kbx-space-2);flex-wrap:wrap}
|
|
</style>
|