Files
cn-rdms-web/src/views/personal-center/work-report/index.vue
dk d53a8dfae5 fix(加班申请): 去掉撤销相关的状态和动作。
feat(工作报告): 开发工作报告功能
2026-06-11 10:56:24 +08:00

242 lines
7.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { onBeforeRouteLeave } from 'vue-router';
import { fetchGetProjectReportOwnerProjectOptions } from '@/service/api';
import { useAuth } from '@/hooks/business/auth';
import WorkReportCreateDialog from './shared/components/create-dialog.vue';
import WorkReportPrototypePageDialog from './shared/components/prototype-page-dialog.vue';
import WorkReportTabs from './shared/components/tabs.vue';
import {
WORK_REPORT_PROJECT_OWNER_PERMISSION,
WORK_REPORT_TYPE_LABEL,
type WorkReportRow,
type WorkReportType
} from './shared/types';
import WeeklyReportIndex from './weekly/index.vue';
import WeeklyReportApprovalRecordDialog from './weekly/modules/approval-record-dialog.vue';
import MonthlyReportIndex from './monthly/index.vue';
import MonthlyReportApprovalRecordDialog from './monthly/modules/approval-record-dialog.vue';
import ProjectReportIndex from './project/index.vue';
import ProjectReportApprovalRecordDialog from './project/modules/approval-record-dialog.vue';
defineOptions({ name: 'PersonalCenterWorkReport' });
type PageDialogMode = 'add' | 'edit' | 'detail';
type ReportListExpose = {
reload: (page?: number) => Promise<void>;
};
const { hasAuth } = useAuth();
const activeTab = ref<WorkReportType>('weekly');
const createVisible = ref(false);
const pageDialogVisible = ref(false);
const pageDialogMode = ref<PageDialogMode>('detail');
const approvalRecordVisible = ref(false);
const currentReportType = ref<WorkReportType>('weekly');
const currentRow = ref<WorkReportRow | null>(null);
const initialPeriod = ref<{
periodKey: string;
periodLabel: string;
periodStartDate: string;
periodEndDate: string;
} | null>(null);
const initialProjectId = ref('');
const initialFlag = ref(1);
const projectOptions = ref<Api.WorkReport.Project.ProjectReportOwnerProjectOption[]>([]);
const weeklyRef = ref<ReportListExpose | null>(null);
const monthlyRef = ref<ReportListExpose | null>(null);
const projectRef = ref<ReportListExpose | null>(null);
const canShowProjectTab = computed(() => hasAuth(WORK_REPORT_PROJECT_OWNER_PERMISSION));
/** 项目选项是否加载成功(用于项目半月报列表内部判断) */
const projectOptionsLoaded = ref(false);
const visibleTabs = computed<Array<{ label: string; name: WorkReportType }>>(() => {
const tabs: Array<{ label: string; name: WorkReportType }> = [
{ label: WORK_REPORT_TYPE_LABEL.weekly, name: 'weekly' },
{ label: WORK_REPORT_TYPE_LABEL.monthly, name: 'monthly' }
];
if (canShowProjectTab.value) {
tabs.push({ label: WORK_REPORT_TYPE_LABEL.project, name: 'project' });
}
return tabs;
});
const currentApprovalRecordDialogComponent = computed(() => {
if (currentReportType.value === 'monthly') return MonthlyReportApprovalRecordDialog;
if (currentReportType.value === 'project') return ProjectReportApprovalRecordDialog;
return WeeklyReportApprovalRecordDialog;
});
function getListRef(reportType: WorkReportType) {
if (reportType === 'monthly') return monthlyRef.value;
if (reportType === 'project') return projectRef.value;
return weeklyRef.value;
}
async function loadProjectOptions() {
if (!canShowProjectTab.value) return;
const { error, data } = await fetchGetProjectReportOwnerProjectOptions();
projectOptions.value = error || !data ? [] : data;
projectOptionsLoaded.value = !error;
}
function openCreate(reportType: WorkReportType) {
currentReportType.value = reportType;
createVisible.value = true;
}
function handleCreateConfirm(
payload:
| { reportType: 'weekly' | 'monthly'; period: typeof initialPeriod.value extends infer T ? T : never }
| {
reportType: 'project';
projectId: string;
flag: number;
period: typeof initialPeriod.value extends infer T ? T : never;
}
) {
currentReportType.value = payload.reportType;
pageDialogMode.value = 'add';
currentRow.value = null;
initialPeriod.value = payload.period as typeof initialPeriod.value;
initialProjectId.value = 'projectId' in payload ? payload.projectId : '';
initialFlag.value = 'flag' in payload ? payload.flag : 1;
pageDialogVisible.value = true;
}
function openEdit(reportType: WorkReportType, row: WorkReportRow) {
currentReportType.value = reportType;
pageDialogMode.value = 'edit';
currentRow.value = row;
initialPeriod.value = null;
pageDialogVisible.value = true;
}
function openDetail(reportType: WorkReportType, row: WorkReportRow) {
currentReportType.value = reportType;
pageDialogMode.value = 'detail';
currentRow.value = row;
initialPeriod.value = null;
pageDialogVisible.value = true;
}
function openApprovalRecord(reportType: WorkReportType, row: WorkReportRow) {
currentReportType.value = reportType;
currentRow.value = row;
approvalRecordVisible.value = true;
}
function handleTabChange(tab: WorkReportType) {
activeTab.value = tab;
getListRef(tab)?.reload(1);
}
async function reloadReport(reportType = currentReportType.value) {
await getListRef(reportType)?.reload();
}
function handleSubmitted() {
pageDialogVisible.value = false;
reloadReport(currentReportType.value);
}
function closeFloatingPanels() {
createVisible.value = false;
pageDialogVisible.value = false;
approvalRecordVisible.value = false;
}
onMounted(async () => {
await loadProjectOptions();
});
onBeforeRouteLeave(() => {
closeFloatingPanels();
});
</script>
<template>
<div
class="work-report-page-shell min-h-560px gap-16px overflow-hidden xl:grid xl:grid-cols-[240px_minmax(0,1fr)] lt-xl:flex lt-xl:flex-col lt-xl:overflow-auto"
>
<!-- 左侧报告类型导航 -->
<div class="flex-col-stretch gap-16px xl:min-h-0">
<WorkReportTabs :active-tab="activeTab" :tabs="visibleTabs" @update:active-tab="handleTabChange" />
</div>
<!-- 右侧搜索区 + 列表区 -->
<div class="flex-col-stretch gap-16px xl:min-h-0">
<WeeklyReportIndex
v-show="activeTab === 'weekly'"
ref="weeklyRef"
class="flex-1-hidden"
@create="openCreate('weekly')"
@edit="openEdit('weekly', $event)"
@detail="openDetail('weekly', $event)"
@approval-record="openApprovalRecord('weekly', $event)"
/>
<MonthlyReportIndex
v-show="activeTab === 'monthly'"
ref="monthlyRef"
class="flex-1-hidden"
@create="openCreate('monthly')"
@edit="openEdit('monthly', $event)"
@detail="openDetail('monthly', $event)"
@approval-record="openApprovalRecord('monthly', $event)"
/>
<ProjectReportIndex
v-if="canShowProjectTab"
v-show="activeTab === 'project'"
ref="projectRef"
class="flex-1-hidden"
:project-options="projectOptions"
:project-options-loaded="projectOptionsLoaded"
@create="openCreate('project')"
@edit="openEdit('project', $event)"
@detail="openDetail('project', $event)"
@approval-record="openApprovalRecord('project', $event)"
/>
</div>
<WorkReportCreateDialog
v-model:visible="createVisible"
:default-report-type="currentReportType"
:project-visible="canShowProjectTab"
:project-options="projectOptions"
@confirm="handleCreateConfirm"
/>
<WorkReportPrototypePageDialog
v-model:visible="pageDialogVisible"
:mode="pageDialogMode"
scene="fill"
:report-type="currentReportType"
:row-data="currentRow"
:initial-period="initialPeriod"
:initial-project-id="initialProjectId"
:initial-flag="initialFlag"
@submitted="handleSubmitted"
/>
<component
:is="currentApprovalRecordDialogComponent"
v-model:visible="approvalRecordVisible"
:row-data="currentRow"
/>
</div>
</template>
<style scoped>
.work-report-page-shell {
height: 100%;
}
</style>