<script lang="ts" setup>
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { HrmWorkHourStatisticsApi } from '#/api/hrm/work-hour-statistics';
|
|
import { onBeforeUnmount, onMounted, ref, useTemplateRef } from 'vue';
|
|
import { Page } from '@vben/common-ui';
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
|
import { Tabs } from 'ant-design-vue';
|
|
import {
|
getEmployeeWorkHourSummary,
|
getTeamWorkHourSummary,
|
} from '#/api/hrm/work-hour-statistics';
|
|
/** HRM 工时统计(考勤口径 + 报工口径) */
|
defineOptions({ name: 'HrmWorkHourStatistics' });
|
|
const activeTab = ref<'employee' | 'team'>('employee');
|
|
const contentRef = useTemplateRef('contentRef');
|
let resizeObserver: ResizeObserver | undefined;
|
|
/** 计算表格高度:内容区可用高度 - Tabs 导航等固定开销,表格撑满页面 */
|
function calcTableHeight() {
|
const el = contentRef.value;
|
if (!el) return;
|
const height = Math.max(el.clientHeight - 115, 240);
|
employeeGridApi.setGridOptions({ height });
|
teamGridApi.setGridOptions({ height });
|
}
|
|
onMounted(() => {
|
calcTableHeight();
|
resizeObserver = new ResizeObserver(calcTableHeight);
|
if (contentRef.value) resizeObserver.observe(contentRef.value);
|
});
|
|
onBeforeUnmount(() => {
|
resizeObserver?.disconnect();
|
});
|
|
const [EmployeeGrid, employeeGridApi] = useVbenVxeGrid({
|
formOptions: {
|
schema: [
|
{
|
fieldName: 'dateRange',
|
label: '日期范围',
|
component: 'RangePicker',
|
componentProps: {
|
class: '!w-full',
|
valueFormat: 'YYYY-MM-DD',
|
placeholder: ['开始日期', '结束日期'],
|
},
|
},
|
],
|
},
|
gridOptions: {
|
columns: [
|
{ field: 'userName', title: '员工姓名', minWidth: 140 },
|
{ field: 'deptName', title: '部门', minWidth: 140 },
|
{ field: 'workDays', title: '出勤天数', width: 110 },
|
{ field: 'workHours', title: '正常工时(人时)', width: 150 },
|
{ field: 'overtimeHours', title: '加班工时(人时)', width: 150 },
|
],
|
height: 400,
|
keepSource: true,
|
// 返回裸数组,需关闭分页
|
pagerConfig: { enabled: false },
|
proxyConfig: {
|
ajax: {
|
query: async (_params, formValues) => {
|
const range = formValues?.dateRange ?? [];
|
return await getEmployeeWorkHourSummary({
|
startDate: range?.[0],
|
endDate: range?.[1],
|
});
|
},
|
},
|
},
|
rowConfig: { keyField: 'userId', isHover: true },
|
toolbarConfig: { refresh: true, search: true },
|
} as VxeTableGridOptions<HrmWorkHourStatisticsApi.EmployeeWorkHour>,
|
});
|
|
const [TeamGrid, teamGridApi] = useVbenVxeGrid({
|
formOptions: {
|
schema: [
|
{
|
fieldName: 'timeRange',
|
label: '日期范围',
|
component: 'RangePicker',
|
componentProps: {
|
class: '!w-full',
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
placeholder: ['开始时间', '结束时间'],
|
},
|
},
|
],
|
},
|
gridOptions: {
|
columns: [
|
{ field: 'teamName', title: '班组名称', minWidth: 160 },
|
{ field: 'taskCount', title: '任务数', width: 100 },
|
{ field: 'totalDuration', title: '总生产时长(人日)', width: 160 },
|
{ field: 'workHours', title: '总工时(人时)', width: 150 },
|
],
|
height: 400,
|
keepSource: true,
|
pagerConfig: { enabled: false },
|
proxyConfig: {
|
ajax: {
|
query: async (_params, formValues) => {
|
const range = formValues?.timeRange ?? [];
|
return await getTeamWorkHourSummary({
|
startTime: range?.[0],
|
endTime: range?.[1],
|
});
|
},
|
},
|
},
|
rowConfig: { keyField: 'teamId', isHover: true },
|
toolbarConfig: { refresh: true, search: true },
|
} as VxeTableGridOptions<HrmWorkHourStatisticsApi.TeamWorkHour>,
|
});
|
</script>
|
|
<template>
|
<Page auto-content-height>
|
<div ref="contentRef" class="flex h-full w-full flex-col">
|
<Tabs v-model:active-key="activeTab" class="min-h-0 flex-1">
|
<Tabs.TabPane key="employee" tab="员工工时(考勤口径)">
|
<EmployeeGrid table-title="员工工时统计" />
|
</Tabs.TabPane>
|
<Tabs.TabPane key="team" tab="班组工时(报工口径)">
|
<TeamGrid table-title="班组工时统计" />
|
</Tabs.TabPane>
|
</Tabs>
|
</div>
|
</Page>
|
</template>
|