fix(加班申请、工作报告、我的绩效): 重构页面样式、修复一系列bug、对不合理的地方进行调整。
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
<script setup lang="tsx">
|
||||
/* eslint-disable no-void */
|
||||
import { computed, markRaw, reactive, ref } from 'vue';
|
||||
import { computed, markRaw, reactive, ref, watch } from 'vue';
|
||||
import { ElMessageBox, ElTag } from 'element-plus';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
fetchDeleteMonthlyReport,
|
||||
fetchExportMonthlyReportContent,
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
import { useAuth } from '@/hooks/business/auth';
|
||||
import { useUIPaginatedTable } from '@/hooks/common/table';
|
||||
import BusinessTableActionCell, { type BusinessTableAction } from '@/components/custom/business-table-action-cell';
|
||||
import { type TeamViewContext, resolveTeamQueryUserIds } from '@/views/personal-center/shared/team-dashboard';
|
||||
import { type TeamViewContext } from '@/views/personal-center/shared/team-dashboard';
|
||||
import {
|
||||
type WorkReportRow,
|
||||
createMonthlySearchParams,
|
||||
@@ -27,8 +28,7 @@ import {
|
||||
resolveWorkReportStatusTagType,
|
||||
transformWorkReportPage
|
||||
} from '../shared/types';
|
||||
import { resolveWorkReportSummaryPeriod } from '../shared/utils';
|
||||
import TeamReportSummary from '../shared/components/team-report-summary.vue';
|
||||
import { buildMonthlyPeriodFromMonth, resolveWorkReportSummaryPeriod } from '../shared/utils';
|
||||
import MonthlyReportSearch from './modules/search-panel.vue';
|
||||
import IconMdiDeleteOutline from '~icons/mdi/delete-outline';
|
||||
import IconMdiEyeOutline from '~icons/mdi/eye-outline';
|
||||
@@ -41,6 +41,7 @@ defineOptions({ name: 'MonthlyWorkReportIndex' });
|
||||
|
||||
const props = defineProps<{
|
||||
teamContext?: TeamViewContext | null;
|
||||
subordinateOptions?: Array<{ label: string; value: string }>;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -68,8 +69,45 @@ const ACTION_ICON_MAP = {
|
||||
|
||||
const isTeamMode = computed(() => props.teamContext?.mode === 'team');
|
||||
const isTeamRootSelected = computed(() => Boolean(isTeamMode.value && props.teamContext?.isRootSelected));
|
||||
const currentTeamReporterIds = computed(() => resolveTeamQueryUserIds(props.teamContext));
|
||||
const currentTeamReporterIds = computed(() => {
|
||||
if (!isTeamMode.value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isTeamRootSelected.value) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return props.teamContext?.selectedUserIds ?? [];
|
||||
});
|
||||
const resolvedTeamReporterIds = computed(() => {
|
||||
if (!isTeamMode.value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (searchParams.reporterIds?.length) {
|
||||
return searchParams.reporterIds;
|
||||
}
|
||||
|
||||
return currentTeamReporterIds.value;
|
||||
});
|
||||
const reportTitle = computed(() => getWorkReportTypeDisplayLabel('monthly', isTeamMode.value));
|
||||
const normalizedPeriodRange = computed(() => {
|
||||
const periodRange = searchParams.periodStartDate;
|
||||
if (!periodRange?.length) {
|
||||
return periodRange;
|
||||
}
|
||||
|
||||
const [startDate, endDate] = periodRange;
|
||||
const start = dayjs(startDate);
|
||||
const end = dayjs(endDate || startDate);
|
||||
|
||||
if (!start.isValid() || !end.isValid()) {
|
||||
return periodRange;
|
||||
}
|
||||
|
||||
return [start.startOf('month').format('YYYY-MM-DD'), end.endOf('month').format('YYYY-MM-DD')];
|
||||
});
|
||||
|
||||
const table = useUIPaginatedTable<
|
||||
Awaited<ReturnType<typeof fetchGetMonthlyReportPage>>,
|
||||
@@ -79,52 +117,104 @@ const table = useUIPaginatedTable<
|
||||
api: () =>
|
||||
fetchGetMonthlyReportPage({
|
||||
...searchParams,
|
||||
reporterIds: currentTeamReporterIds.value
|
||||
periodStartDate: normalizedPeriodRange.value,
|
||||
reporterIds: resolvedTeamReporterIds.value
|
||||
}),
|
||||
transform: response => transformWorkReportPage(response, searchParams.pageNo ?? 1, searchParams.pageSize ?? 10),
|
||||
onPaginationParamsChange: params => {
|
||||
searchParams.pageNo = params.currentPage ?? 1;
|
||||
searchParams.pageSize = params.pageSize ?? 10;
|
||||
},
|
||||
columns: () => [
|
||||
{ prop: 'index', type: 'index', label: '序号', width: 64 },
|
||||
...(isTeamMode.value ? [{ prop: 'reporterName', label: '提交人', minWidth: 100, showOverflowTooltip: true }] : []),
|
||||
{ prop: 'periodLabel', label: '月份', minWidth: 80, formatter: row => formatPeriod(row) },
|
||||
{
|
||||
prop: 'reporterDeptName',
|
||||
label: '部门',
|
||||
minWidth: 80,
|
||||
showOverflowTooltip: true,
|
||||
formatter: row => row.reporterDeptName || '--'
|
||||
},
|
||||
{ prop: 'supervisorName', label: '直属上级', minWidth: 80 },
|
||||
{ prop: 'totalWorkHours', label: '总工时', minWidth: 80, formatter: row => formatEmptyText(row.totalWorkHours) },
|
||||
{
|
||||
prop: 'statusCode',
|
||||
label: '状态',
|
||||
minWidth: 80,
|
||||
align: 'center',
|
||||
formatter: row => (
|
||||
<ElTag type={resolveWorkReportStatusTagType(row.statusCode)}>
|
||||
{getWorkReportStatusLabel(row.statusCode, row.statusName)}
|
||||
</ElTag>
|
||||
)
|
||||
},
|
||||
{ prop: 'submitTime', label: '提交时间', minWidth: 100, formatter: row => formatDateTime(row.submitTime) },
|
||||
{ prop: 'approvalTime', label: '审批时间', minWidth: 100, formatter: row => formatDateTime(row.approvalTime) },
|
||||
{
|
||||
prop: 'operate',
|
||||
label: '操作',
|
||||
width: isTeamMode.value ? 140 : 180,
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
formatter: row => <BusinessTableActionCell actions={getRowActions(row)} variant="icon" />
|
||||
columns: () => {
|
||||
const cols: UI.TableColumn<Api.WorkReport.Monthly.MonthlyReport>[] = [
|
||||
{ prop: 'index', type: 'index', label: '序号', width: 64 },
|
||||
{ prop: 'periodLabel', label: '月份', minWidth: 80, formatter: row => formatPeriod(row) }
|
||||
];
|
||||
|
||||
if (isTeamMode.value) {
|
||||
cols.push({ prop: 'reporterName', label: '提交人', minWidth: 100, showOverflowTooltip: true });
|
||||
}
|
||||
]
|
||||
|
||||
cols.push(
|
||||
{
|
||||
prop: 'reporterDeptName',
|
||||
label: '部门',
|
||||
minWidth: 80,
|
||||
showOverflowTooltip: true,
|
||||
formatter: row => row.reporterDeptName || '--'
|
||||
},
|
||||
{ prop: 'supervisorName', label: '直属上级', minWidth: 80 },
|
||||
{ prop: 'totalWorkHours', label: '总工时', minWidth: 80, formatter: row => formatEmptyText(row.totalWorkHours) },
|
||||
{
|
||||
prop: 'statusCode',
|
||||
label: '状态',
|
||||
minWidth: 80,
|
||||
align: 'center',
|
||||
formatter: row => (
|
||||
<ElTag type={resolveWorkReportStatusTagType(row.statusCode)}>
|
||||
{getWorkReportStatusLabel(row.statusCode, row.statusName)}
|
||||
</ElTag>
|
||||
)
|
||||
},
|
||||
{ prop: 'submitTime', label: '提交时间', minWidth: 100, formatter: row => formatDateTime(row.submitTime) },
|
||||
{ prop: 'approvalTime', label: '审批时间', minWidth: 100, formatter: row => formatDateTime(row.approvalTime) },
|
||||
{
|
||||
prop: 'operate',
|
||||
label: '操作',
|
||||
width: isTeamMode.value ? 140 : 180,
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
formatter: row => <BusinessTableActionCell actions={getRowActions(row)} variant="icon" />
|
||||
}
|
||||
);
|
||||
|
||||
return cols;
|
||||
}
|
||||
});
|
||||
|
||||
// 团队统计始终使用当前周期(本月),不跟随列表第一条数据的周期
|
||||
const summaryPeriod = computed(() => resolveWorkReportSummaryPeriod('monthly'));
|
||||
const summaryPeriod = computed(() =>
|
||||
resolveWorkReportSummaryPeriod('monthly', {
|
||||
periodRange: normalizedPeriodRange.value
|
||||
})
|
||||
);
|
||||
const summaryPeriodKeys = computed(() => {
|
||||
const dateRange = normalizedPeriodRange.value;
|
||||
const fallbackKey = summaryPeriod.value.periodKey;
|
||||
|
||||
if (!dateRange?.length) {
|
||||
return fallbackKey ? [fallbackKey] : [];
|
||||
}
|
||||
|
||||
const [startDate, endDate] = dateRange;
|
||||
const start = dayjs(startDate);
|
||||
const end = dayjs(endDate || startDate);
|
||||
|
||||
if (!start.isValid() || !end.isValid()) {
|
||||
return fallbackKey ? [fallbackKey] : [];
|
||||
}
|
||||
|
||||
const keys: string[] = [];
|
||||
const endBoundary = end.endOf('month');
|
||||
|
||||
for (
|
||||
let cursor = start.startOf('month');
|
||||
cursor.isBefore(endBoundary, 'month') || cursor.isSame(endBoundary, 'month');
|
||||
cursor = cursor.add(1, 'month')
|
||||
) {
|
||||
keys.push(buildMonthlyPeriodFromMonth(cursor).periodKey);
|
||||
}
|
||||
|
||||
return keys;
|
||||
});
|
||||
const hasSearchedDateRange = computed(() => searchParams.periodStartDate?.length === 2);
|
||||
|
||||
watch(
|
||||
() => isTeamMode.value,
|
||||
() => {
|
||||
table.reloadColumns();
|
||||
}
|
||||
);
|
||||
|
||||
function getRowActions(row: Api.WorkReport.Monthly.MonthlyReport): BusinessTableAction[] {
|
||||
const actions: BusinessTableAction[] = [
|
||||
@@ -266,7 +356,8 @@ function createExportSearchParams() {
|
||||
const { pageNo: _pageNo, pageSize: _pageSize, ...params } = searchParams;
|
||||
return {
|
||||
...params,
|
||||
reporterIds: currentTeamReporterIds.value
|
||||
periodStartDate: normalizedPeriodRange.value,
|
||||
reporterIds: resolvedTeamReporterIds.value
|
||||
};
|
||||
}
|
||||
|
||||
@@ -332,31 +423,42 @@ async function loadTeamSummary() {
|
||||
return;
|
||||
}
|
||||
|
||||
const dateRange = normalizedPeriodRange.value;
|
||||
const summaryParams: Api.WorkReport.Common.TeamReportSummaryParams = { reportType: 'monthly' };
|
||||
|
||||
if (dateRange?.length === 2) {
|
||||
summaryParams.periodStartDate = dateRange[0];
|
||||
summaryParams.periodEndDate = dateRange[1];
|
||||
} else {
|
||||
summaryParams.periodKey = summaryPeriod.value.periodKey;
|
||||
}
|
||||
|
||||
teamSummaryLoading.value = true;
|
||||
const { error, data } = await fetchGetTeamReportSummary({
|
||||
reportType: 'monthly',
|
||||
periodKey: summaryPeriod.value.periodKey
|
||||
});
|
||||
const { error, data } = await fetchGetTeamReportSummary(summaryParams);
|
||||
teamSummaryLoading.value = false;
|
||||
|
||||
teamSummary.value = error || !data ? null : data;
|
||||
}
|
||||
|
||||
defineExpose({ reload });
|
||||
defineExpose({
|
||||
reload,
|
||||
teamSummary,
|
||||
teamSummaryLoading,
|
||||
summaryPeriod,
|
||||
summaryPeriodKeys,
|
||||
hasSearchedDateRange,
|
||||
loadTeamSummary
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-col-stretch gap-16px overflow-hidden">
|
||||
<MonthlyReportSearch v-model:model="searchParams" @reset="resetSearchParams" @search="handleSearch" />
|
||||
|
||||
<TeamReportSummary
|
||||
v-if="isTeamRootSelected"
|
||||
report-type="monthly"
|
||||
:period-key="summaryPeriod.periodKey"
|
||||
:period-label="formatPeriod(summaryPeriod)"
|
||||
:loading="teamSummaryLoading"
|
||||
:summary="teamSummary"
|
||||
@reminded="loadTeamSummary"
|
||||
<MonthlyReportSearch
|
||||
v-model:model="searchParams"
|
||||
:team-mode="isTeamMode"
|
||||
:subordinate-options="props.subordinateOptions"
|
||||
@reset="resetSearchParams"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
|
||||
<ElCard class="flex-1-hidden card-wrapper" body-class="business-table-card-body">
|
||||
|
||||
Reference in New Issue
Block a user