2026-06-01 21:37:08 +08:00
|
|
|
<script setup lang="ts">
|
2026-06-11 10:56:24 +08:00
|
|
|
import { ref, watch } from 'vue';
|
2026-06-01 21:37:08 +08:00
|
|
|
import { fetchGetOvertimeApplicationDetail } from '@/service/api';
|
|
|
|
|
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
|
2026-06-11 10:56:24 +08:00
|
|
|
import { formatOvertimeDate, formatOvertimeDateTime } from './overtime-application-shared';
|
|
|
|
|
import IconMdiCheckCircleOutline from '~icons/mdi/check-circle-outline';
|
|
|
|
|
import IconMdiCloseCircleOutline from '~icons/mdi/close-circle-outline';
|
2026-06-01 21:37:08 +08:00
|
|
|
|
|
|
|
|
defineOptions({ name: 'OvertimeApplicationDetailDialog' });
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
rowData?: Api.OvertimeApplication.OvertimeApplication | null;
|
2026-06-11 10:56:24 +08:00
|
|
|
showApprovalActions?: boolean;
|
|
|
|
|
actionLoading?: boolean;
|
2026-06-01 21:37:08 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-11 10:56:24 +08:00
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
|
|
|
showApprovalActions: false,
|
|
|
|
|
actionLoading: false
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
approve: [];
|
|
|
|
|
reject: [];
|
|
|
|
|
}>();
|
2026-06-01 21:37:08 +08:00
|
|
|
|
|
|
|
|
const visible = defineModel<boolean>('visible', {
|
|
|
|
|
default: false
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
const detailData = ref<Api.OvertimeApplication.OvertimeApplication | null>(null);
|
|
|
|
|
|
|
|
|
|
async function loadDetail() {
|
|
|
|
|
if (!props.rowData?.id) {
|
|
|
|
|
detailData.value = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loading.value = true;
|
|
|
|
|
const { error, data } = await fetchGetOvertimeApplicationDetail(props.rowData.id);
|
|
|
|
|
loading.value = false;
|
|
|
|
|
|
|
|
|
|
detailData.value = error || !data ? props.rowData : data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => visible.value,
|
|
|
|
|
value => {
|
|
|
|
|
if (value) {
|
|
|
|
|
loadDetail();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
2026-06-11 10:56:24 +08:00
|
|
|
<BusinessFormDialog
|
|
|
|
|
v-model="visible"
|
|
|
|
|
title="加班申请详情"
|
|
|
|
|
preset="md"
|
|
|
|
|
:loading="loading"
|
|
|
|
|
:show-footer="props.showApprovalActions"
|
|
|
|
|
>
|
|
|
|
|
<ElDescriptions v-if="detailData" class="overtime-application-detail-dialog__descriptions" :column="2" border>
|
|
|
|
|
<ElDescriptionsItem label="申请人" label-class-name="overtime-application-detail-dialog__label">
|
2026-06-01 21:37:08 +08:00
|
|
|
{{ detailData.applicantName }}
|
|
|
|
|
</ElDescriptionsItem>
|
2026-06-11 10:56:24 +08:00
|
|
|
<ElDescriptionsItem label="加班日期" label-class-name="overtime-application-detail-dialog__label--compact">
|
|
|
|
|
{{ formatOvertimeDate(detailData.overtimeDate) }}
|
|
|
|
|
</ElDescriptionsItem>
|
|
|
|
|
<ElDescriptionsItem label="加班时长" label-class-name="overtime-application-detail-dialog__label">
|
|
|
|
|
{{ detailData.overtimeDuration }}
|
|
|
|
|
</ElDescriptionsItem>
|
|
|
|
|
<ElDescriptionsItem label="提交时间" label-class-name="overtime-application-detail-dialog__label--compact">
|
|
|
|
|
{{ formatOvertimeDateTime(detailData.submitTime) }}
|
|
|
|
|
</ElDescriptionsItem>
|
|
|
|
|
<ElDescriptionsItem label="加班原因" :span="2" label-class-name="overtime-application-detail-dialog__label">
|
|
|
|
|
{{ detailData.overtimeReason }}
|
|
|
|
|
</ElDescriptionsItem>
|
|
|
|
|
<ElDescriptionsItem label="加班内容" :span="2" label-class-name="overtime-application-detail-dialog__label">
|
|
|
|
|
{{ detailData.overtimeContent }}
|
2026-06-01 21:37:08 +08:00
|
|
|
</ElDescriptionsItem>
|
|
|
|
|
</ElDescriptions>
|
|
|
|
|
<ElEmpty v-else description="未获取到加班申请详情" />
|
2026-06-11 10:56:24 +08:00
|
|
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
<div class="overtime-application-detail-dialog__footer">
|
|
|
|
|
<ElButton
|
|
|
|
|
class="overtime-application-detail-dialog__approve-btn"
|
|
|
|
|
type="success"
|
|
|
|
|
:loading="props.actionLoading"
|
|
|
|
|
:disabled="props.actionLoading || !detailData"
|
|
|
|
|
@click="emit('approve')"
|
|
|
|
|
>
|
|
|
|
|
<template #icon>
|
|
|
|
|
<IconMdiCheckCircleOutline />
|
|
|
|
|
</template>
|
|
|
|
|
通过
|
|
|
|
|
</ElButton>
|
|
|
|
|
<ElButton type="danger" plain :disabled="props.actionLoading || !detailData" @click="emit('reject')">
|
|
|
|
|
<template #icon>
|
|
|
|
|
<IconMdiCloseCircleOutline />
|
|
|
|
|
</template>
|
|
|
|
|
退回
|
|
|
|
|
</ElButton>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
2026-06-01 21:37:08 +08:00
|
|
|
</BusinessFormDialog>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2026-06-11 10:56:24 +08:00
|
|
|
.overtime-application-detail-dialog__footer {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
gap: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.overtime-application-detail-dialog__approve-btn {
|
|
|
|
|
--el-button-bg-color: #0f766e;
|
|
|
|
|
--el-button-border-color: #0f766e;
|
|
|
|
|
--el-button-hover-bg-color: #115e59;
|
|
|
|
|
--el-button-hover-border-color: #115e59;
|
|
|
|
|
--el-button-active-bg-color: #134e4a;
|
|
|
|
|
--el-button-active-border-color: #134e4a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.overtime-application-detail-dialog__descriptions .el-descriptions__cell) {
|
|
|
|
|
line-height: 1.7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.overtime-application-detail-dialog__label),
|
|
|
|
|
:deep(.overtime-application-detail-dialog__label--compact) {
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.overtime-application-detail-dialog__label) {
|
|
|
|
|
width: 96px;
|
|
|
|
|
min-width: 96px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.overtime-application-detail-dialog__label--compact) {
|
|
|
|
|
width: 86px;
|
|
|
|
|
min-width: 86px;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-01 21:37:08 +08:00
|
|
|
:deep(.overtime-application-detail-dialog__readonly-input .el-input__wrapper) {
|
|
|
|
|
background: linear-gradient(180deg, rgb(241 245 249 / 98%), rgb(226 232 240 / 94%)), rgb(241 245 249);
|
|
|
|
|
box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
|
|
|
|
|
cursor: default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.overtime-application-detail-dialog__readonly-input .el-input__wrapper:hover),
|
|
|
|
|
:deep(.overtime-application-detail-dialog__readonly-input.is-focus .el-input__wrapper) {
|
|
|
|
|
box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.overtime-application-detail-dialog__readonly-input .el-input__inner) {
|
|
|
|
|
color: rgb(51 65 85 / 96%);
|
|
|
|
|
cursor: default;
|
|
|
|
|
-webkit-text-fill-color: rgb(51 65 85 / 96%);
|
|
|
|
|
}
|
|
|
|
|
</style>
|