242 lines
7.7 KiB
Vue
242 lines
7.7 KiB
Vue
<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>
|