fix(加班申请): 去掉撤销相关的状态和动作。

feat(工作报告): 开发工作报告功能
This commit is contained in:
dk
2026-06-11 10:56:24 +08:00
parent 2e369b23a9
commit d53a8dfae5
56 changed files with 14312 additions and 2910 deletions

View File

@@ -3,14 +3,23 @@ import { computed, markRaw, onMounted, ref, watch } from 'vue';
import type { RouteKey } from '@elegant-router/types';
import {
fetchApproveOvertimeApplication,
fetchGetMonthlyReportApprovalPage,
fetchGetOvertimeApplicationApprovalPage,
fetchGetProjectReportApprovalPage,
fetchGetWeeklyReportApprovalPage,
fetchRejectOvertimeApplication
} from '@/service/api';
import { useRouterPush } from '@/hooks/common/router';
import PersonalItemOperateDialog from '@/views/personal-center/my-item/modules/personal-item-operate-dialog.vue';
import OvertimeApplicationActionDialog from '@/views/personal-center/overtime-application/modules/overtime-application-action-dialog.vue';
import OvertimeApplicationDetailDialog from '@/views/personal-center/overtime-application/modules/overtime-application-detail-dialog.vue';
import OvertimeApplicationStatusLogDialog from '@/views/personal-center/overtime-application/modules/overtime-application-status-log-dialog.vue';
import WorkReportPrototypePageDialog from '@/views/personal-center/work-report/shared/components/prototype-page-dialog.vue';
import {
WORK_REPORT_TYPE_LABEL,
type WorkReportRow,
type WorkReportType,
formatPeriod
} from '@/views/personal-center/work-report/shared/types';
import {
type WorkbenchTodoDeadlineFilter,
type WorkbenchTodoItem,
@@ -24,14 +33,11 @@ import {
import { workbenchTodoMock } from '../mock';
import { useWorkbenchRefresh } from '../composables/use-workbench-refresh';
import WorkbenchModuleCard from './workbench-module-card.vue';
import IconMdiCheckCircleOutline from '~icons/mdi/check-circle-outline';
import IconMdiCloseCircleOutline from '~icons/mdi/close-circle-outline';
import IconMdiEyeOutline from '~icons/mdi/eye-outline';
import IconMdiHistory from '~icons/mdi/history';
type SortKey = 'created' | 'priority' | 'deadline';
type OvertimeApprovalActionType = 'approve' | 'reject';
type ApprovalBizType = 'overtime_application';
type ApprovalBizType = 'overtime_application' | WorkReportType;
defineOptions({ name: 'WorkbenchTodoPanel' });
@@ -53,7 +59,7 @@ const PAGE_SIZE = 5;
const activeTab = ref<WorkbenchTodoMainTab>('all');
const activeDeadlineFilter = ref<WorkbenchTodoDeadlineFilter>(null);
const activeApprovalBizType = ref<ApprovalBizType>('overtime_application');
const activeApprovalBizType = ref<ApprovalBizType>('weekly');
const activeSort = ref<SortKey>('deadline');
const currentPage = ref(1);
@@ -83,31 +89,37 @@ const deadlineFilters: Array<{ key: Exclude<WorkbenchTodoDeadlineFilter, null>;
];
const approvalBizTabs: Array<{ key: ApprovalBizType; label: string }> = [
{ key: 'weekly', label: '周报' },
{ key: 'monthly', label: '月报' },
{ key: 'project', label: '项目半月报' },
{ key: 'overtime_application', label: '加班申请' }
];
const allItems = computed(() => buildWorkbenchTodoItems(workbenchTodoMock));
const overtimeApprovalItems = ref<WorkbenchTodoItem[]>([]);
const overtimeApprovalRows = ref<Api.OvertimeApplication.OvertimeApplication[]>([]);
const workReportApprovalItems = ref<WorkbenchTodoItem[]>([]);
const weeklyApprovalRows = ref<Api.WorkReport.Weekly.WeeklyReport[]>([]);
const monthlyApprovalRows = ref<Api.WorkReport.Monthly.MonthlyReport[]>([]);
const projectApprovalRows = ref<Api.WorkReport.Project.ProjectReport[]>([]);
const mergedItems = computed(() => {
const mockItems = allItems.value.filter(item => item.category !== 'approval');
return [...mockItems, ...overtimeApprovalItems.value];
return [...mockItems, ...overtimeApprovalItems.value, ...workReportApprovalItems.value];
});
const addDialogVisible = ref(false);
const overtimeDetailVisible = ref(false);
const overtimeStatusLogVisible = ref(false);
const overtimeActionVisible = ref(false);
const overtimeActionSubmitting = ref(false);
const currentOvertimeApplication = ref<Api.OvertimeApplication.OvertimeApplication | null>(null);
const currentOvertimeActionType = ref<OvertimeApprovalActionType>('approve');
const workReportDetailVisible = ref(false);
const currentWorkReport = ref<WorkReportRow | null>(null);
const currentWorkReportType = ref<WorkReportType>('weekly');
const OVERTIME_APPROVAL_ACTION_ICONS = {
detail: markRaw(IconMdiEyeOutline),
approve: markRaw(IconMdiCheckCircleOutline),
reject: markRaw(IconMdiCloseCircleOutline),
statusLog: markRaw(IconMdiHistory)
detail: markRaw(IconMdiEyeOutline)
};
function handleOpenAdd() {
@@ -161,13 +173,20 @@ const filteredItems = computed(() => {
const approvalBizTabCounts = computed(() => {
const counts: Record<ApprovalBizType, number> = {
overtime_application: 0
overtime_application: 0,
weekly: 0,
monthly: 0,
project: 0
};
itemsInTab.value.forEach(item => {
if (item.approvalBizType === 'overtime_application') {
counts.overtime_application += 1;
}
if (isWorkReportApprovalBizType(item.approvalBizType)) {
counts[item.approvalBizType] += 1;
}
});
return counts;
@@ -229,10 +248,19 @@ function handleClickItem(item: WorkbenchTodoItem) {
return;
}
if (isWorkReportApprovalBizType(item.approvalBizType)) {
openWorkReportDetail(item);
return;
}
if (!item.routeKey) return;
routerPushByKey(item.routeKey as RouteKey);
}
function isWorkReportApprovalBizType(value?: string): value is WorkReportType {
return value === 'weekly' || value === 'monthly' || value === 'project';
}
function findOvertimeApprovalRow(item: WorkbenchTodoItem) {
if (!item.approvalBizId) {
return null;
@@ -249,23 +277,38 @@ function openOvertimeDetail(item: WorkbenchTodoItem) {
overtimeDetailVisible.value = true;
}
function openOvertimeStatusLog(item: WorkbenchTodoItem) {
const row = findOvertimeApprovalRow(item);
if (!row) return;
function openCurrentOvertimeAction(actionType: OvertimeApprovalActionType) {
if (!currentOvertimeApplication.value) return;
currentOvertimeApplication.value = row;
overtimeStatusLogVisible.value = true;
}
function openOvertimeAction(item: WorkbenchTodoItem, actionType: OvertimeApprovalActionType) {
const row = findOvertimeApprovalRow(item);
if (!row) return;
currentOvertimeApplication.value = row;
currentOvertimeActionType.value = actionType;
overtimeActionVisible.value = true;
}
function findWorkReportApprovalRow(item: WorkbenchTodoItem) {
if (!item.approvalBizId || !isWorkReportApprovalBizType(item.approvalBizType)) {
return null;
}
if (item.approvalBizType === 'weekly') {
return weeklyApprovalRows.value.find(row => row.id === item.approvalBizId) || null;
}
if (item.approvalBizType === 'monthly') {
return monthlyApprovalRows.value.find(row => row.id === item.approvalBizId) || null;
}
return projectApprovalRows.value.find(row => row.id === item.approvalBizId) || null;
}
function openWorkReportDetail(item: WorkbenchTodoItem) {
const row = findWorkReportApprovalRow(item);
if (!row || !isWorkReportApprovalBizType(item.approvalBizType)) return;
currentWorkReport.value = row;
currentWorkReportType.value = item.approvalBizType;
workReportDetailVisible.value = true;
}
async function handleOvertimeActionSubmit(reason: string | null) {
if (!currentOvertimeApplication.value) {
return;
@@ -288,6 +331,11 @@ async function handleOvertimeActionSubmit(reason: string | null) {
await loadOvertimeApprovalItems();
}
async function handleWorkReportSubmitted() {
workReportDetailVisible.value = false;
await loadWorkReportApprovalItems();
}
async function loadOvertimeApprovalItems() {
const { error, data } = await fetchGetOvertimeApplicationApprovalPage({
pageNo: 1,
@@ -323,13 +371,80 @@ async function loadOvertimeApprovalItems() {
);
}
function buildWorkReportApprovalItems<T extends WorkReportRow>(
bizType: WorkReportType,
rows: T[]
): WorkbenchTodoItem[] {
const reportTypeLabel = WORK_REPORT_TYPE_LABEL[bizType];
return buildWorkbenchTodoItems(
rows.map(item => ({
id: `${bizType}-${item.id}`,
category: 'approval',
title: `${reportTypeLabel} · ${formatPeriod(item)} 待审批`,
createdTime: item.submitTime || item.createTime || '',
deadline: item.submitTime || item.createTime || null,
source: `${reportTypeLabel} · ${'projectName' in item ? item.projectName : item.reporterName}`,
priority: 'mid',
approvalBizType: bizType,
approvalBizId: item.id
}))
);
}
async function loadWorkReportApprovalItems() {
const [weeklyResult, monthlyResult, projectResult] = await Promise.all([
fetchGetWeeklyReportApprovalPage({
pageNo: 1,
pageSize: 20,
statusCode: 'pending_approval',
keyword: undefined,
periodStartDate: undefined,
submitTime: undefined,
supervisorName: undefined,
isBusinessTrip: undefined
}),
fetchGetMonthlyReportApprovalPage({
pageNo: 1,
pageSize: 20,
statusCode: 'pending_approval',
keyword: undefined,
periodStartDate: undefined,
submitTime: undefined,
supervisorName: undefined
}),
fetchGetProjectReportApprovalPage({
pageNo: 1,
pageSize: 20,
statusCode: 'pending_approval',
keyword: undefined,
periodStartDate: undefined,
submitTime: undefined,
supervisorName: undefined,
projectId: undefined,
flag: undefined
})
]);
weeklyApprovalRows.value = weeklyResult.error || !weeklyResult.data ? [] : weeklyResult.data.list;
monthlyApprovalRows.value = monthlyResult.error || !monthlyResult.data ? [] : monthlyResult.data.list;
projectApprovalRows.value = projectResult.error || !projectResult.data ? [] : projectResult.data.list;
workReportApprovalItems.value = [
...buildWorkReportApprovalItems('weekly', weeklyApprovalRows.value),
...buildWorkReportApprovalItems('monthly', monthlyApprovalRows.value),
...buildWorkReportApprovalItems('project', projectApprovalRows.value)
];
}
function getDeadlineToneClass(item: WorkbenchTodoItem) {
if (isWorkbenchTodoOverdue(item)) return 'workbench-todo__deadline--rose';
if (item.remainingDays === 0) return 'workbench-todo__deadline--amber';
return 'workbench-todo__deadline--slate';
}
onMounted(loadOvertimeApprovalItems);
onMounted(async () => {
await Promise.all([loadOvertimeApprovalItems(), loadWorkReportApprovalItems()]);
});
</script>
<template>
@@ -447,29 +562,15 @@ onMounted(loadOvertimeApprovalItems);
<component :is="OVERTIME_APPROVAL_ACTION_ICONS.detail" class="text-15px" />
</ElButton>
</ElTooltip>
<ElTooltip content="通过">
<ElButton
link
type="success"
class="workbench-todo__action-btn"
@click="openOvertimeAction(item, 'approve')"
>
<component :is="OVERTIME_APPROVAL_ACTION_ICONS.approve" class="text-15px" />
</ElButton>
</ElTooltip>
<ElTooltip content="退回">
<ElButton
link
type="danger"
class="workbench-todo__action-btn"
@click="openOvertimeAction(item, 'reject')"
>
<component :is="OVERTIME_APPROVAL_ACTION_ICONS.reject" class="text-15px" />
</ElButton>
</ElTooltip>
<ElTooltip content="状态日志">
<ElButton link type="info" class="workbench-todo__action-btn" @click="openOvertimeStatusLog(item)">
<component :is="OVERTIME_APPROVAL_ACTION_ICONS.statusLog" class="text-15px" />
</div>
<div
v-else-if="isWorkReportApprovalBizType(item.approvalBizType)"
class="workbench-todo__actions"
@click.stop
>
<ElTooltip content="详情">
<ElButton link type="primary" class="workbench-todo__action-btn" @click="openWorkReportDetail(item)">
<component :is="OVERTIME_APPROVAL_ACTION_ICONS.detail" class="text-15px" />
</ElButton>
</ElTooltip>
</div>
@@ -503,10 +604,13 @@ onMounted(loadOvertimeApprovalItems);
@submitted="handleAddSubmitted"
/>
<OvertimeApplicationDetailDialog v-model:visible="overtimeDetailVisible" :row-data="currentOvertimeApplication" />
<OvertimeApplicationStatusLogDialog
v-model:visible="overtimeStatusLogVisible"
<OvertimeApplicationDetailDialog
v-model:visible="overtimeDetailVisible"
:row-data="currentOvertimeApplication"
show-approval-actions
:action-loading="overtimeActionSubmitting"
@approve="openCurrentOvertimeAction('approve')"
@reject="openCurrentOvertimeAction('reject')"
/>
<OvertimeApplicationActionDialog
v-model:visible="overtimeActionVisible"
@@ -514,6 +618,15 @@ onMounted(loadOvertimeApprovalItems);
:loading="overtimeActionSubmitting"
@submit="handleOvertimeActionSubmit"
/>
<WorkReportPrototypePageDialog
v-model:visible="workReportDetailVisible"
mode="detail"
scene="approval"
:report-type="currentWorkReportType"
:row-data="currentWorkReport"
@submitted="handleWorkReportSubmitted"
/>
</WorkbenchModuleCard>
</template>