feat(oa/erp): 添加月汇总工时生成功能

- 在 timesheetSummary API 中新增 generateTimesheetSummary 接口用于生成月汇总预览
- 在 timesheetInfo 页面添加生成月汇总工时按钮和对话框界面
- 实现月汇总工时预览功能,包括汇总统计和明细表格展示
- 添加汇总数据提交功能,支持将预览数据保存为正式汇总记录
- 在 timesheetStandardMonth 页面优化月份选择组件,使用日期选择器替代文本输入
- 在 timesheetSummary 页面添加明细调整功能,支持项目和工时调整
- 更新相关类型定义文件以支持新的汇总功能字段结构
dev
Yangk 1 week ago
parent 80b6e26909
commit d6236c06b6

@ -67,10 +67,22 @@ export const delTimesheetSummary = (summaryId: string | number | Array<string |
* @param query
* @returns {*}
*/
export function getErpTimesheetSummaryList (query) {
return request({
url: '/oa/erp/timesheetSummary/getErpTimesheetSummaryList',
method: 'get',
params: query
});
export function getErpTimesheetSummaryList(query) {
return request({
url: '/oa/erp/timesheetSummary/getErpTimesheetSummaryList',
method: 'get',
params: query
});
}
/**
*
* @param query
*/
export const generateTimesheetSummary = (query: any): AxiosPromise<TimesheetSummaryVO> => {
return request({
url: '/oa/erp/timesheetSummary/generate',
method: 'post',
data: query
});
};

@ -1,3 +1,5 @@
import { TimesheetSummaryDetailVO, TimesheetSummaryDetailForm } from '../timesheetSummaryDetail/types';
export interface TimesheetSummaryVO {
/**
* ID
@ -59,6 +61,21 @@ export interface TimesheetSummaryVO {
*/
remark: string;
/**
*
*/
deptName?: string;
/**
*
*/
leaderName?: string;
/**
*
*/
summaryDetailList?: TimesheetSummaryDetailVO[];
}
export interface TimesheetSummaryForm extends BaseEntity {
@ -122,6 +139,11 @@ export interface TimesheetSummaryForm extends BaseEntity {
*/
remark?: string;
/**
*
*/
summaryDetailList?: TimesheetSummaryDetailForm[];
}
export interface TimesheetSummaryQuery extends PageQuery {

@ -11,6 +11,7 @@ export const useUserStore = defineStore('user', () => {
const name = ref('');
const nickname = ref('');
const userId = ref<string | number>('');
const deptId = ref<string | number>('');
const tenantId = ref<string>('');
const avatar = ref('');
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
@ -51,6 +52,7 @@ export const useUserStore = defineStore('user', () => {
nickname.value = user.nickName;
avatar.value = profile;
userId.value = user.userId;
deptId.value = user.deptId;
tenantId.value = user.tenantId;
return Promise.resolve();
}
@ -72,6 +74,7 @@ export const useUserStore = defineStore('user', () => {
return {
userId,
deptId,
tenantId,
token,
nickname,

@ -14,12 +14,12 @@
<el-option v-for="dept in deptList" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
</el-select>
</el-form-item>
<!-- <el-form-item label="起始时间" prop="startTime">-->
<!-- <el-date-picker clearable v-model="queryParams.startTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择起始时间" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="结束时间" prop="endTime">-->
<!-- <el-date-picker clearable v-model="queryParams.endTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择结束时间" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="起始时间" prop="startTime">-->
<!-- <el-date-picker clearable v-model="queryParams.startTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择起始时间" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="结束时间" prop="endTime">-->
<!-- <el-date-picker clearable v-model="queryParams.endTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择结束时间" />-->
<!-- </el-form-item>-->
<el-form-item label="工时填报状态" prop="timesheetStatus">
<el-select v-model="queryParams.timesheetStatus" placeholder="请选择工时填报状态" clearable>
<el-option v-for="dict in timesheet_status" :key="dict.value" :label="dict.label" :value="dict.value" />
@ -53,6 +53,11 @@
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['oa/erp:timesheetInfo:export']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="DocumentAdd" @click="handleGenerateSummary" v-hasPermi="['oa/erp:timesheetSummary:add']"
>生成月汇总工时</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @queryTable="getList"></right-toolbar>
</el-row>
</template>
@ -103,6 +108,55 @@
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 生成汇总工时对话框 -->
<el-dialog :title="generateDialog.title" v-model="generateDialog.visible" width="1000px" append-to-body>
<el-form ref="generateFormRef" :model="generateForm" :rules="generateRules" label-width="100px" inline>
<el-form-item label="汇总月份" prop="monthCode">
<el-date-picker v-model="generateForm.monthCode" type="month" value-format="YYYYMM" placeholder="选择月份" />
</el-form-item>
<el-form-item label="所属部门" prop="deptId">
<el-select v-model="generateForm.deptId" placeholder="请选择部门" filterable>
<el-option v-for="dept in deptList" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleGeneratePreview" :loading="generateLoading">汇总</el-button>
</el-form-item>
</el-form>
<!-- 预览表格 -->
<div v-if="summaryPreviewData" class="mt-4">
<el-descriptions title="汇总统计" :column="4" border class="mb-4">
<el-descriptions-item label="项目总工时">{{ summaryPreviewData.totalProjectHours }}</el-descriptions-item>
<el-descriptions-item label="部门总工时">{{ summaryPreviewData.totalDeptHours }}</el-descriptions-item>
<el-descriptions-item label="总工时">{{ summaryPreviewData.totalHours }}</el-descriptions-item>
<el-descriptions-item label="总人数">{{ summaryPreviewData.staffCount }}</el-descriptions-item>
<el-descriptions-item label="标准天数">{{ summaryPreviewData.standardDays }}</el-descriptions-item>
</el-descriptions>
<el-table :data="summaryPreviewData.summaryDetailList" border max-height="400">
<el-table-column label="序号" type="index" width="55" align="center" />
<el-table-column label="人员" prop="staffName" align="center" />
<el-table-column label="类型" align="center">
<template #default="scope">
<el-tag :type="scope.row.isProject === '1' ? 'success' : 'info'">
{{ scope.row.isProject === '1' ? '项目' : '部门' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="项目" prop="originalProjectName" align="center" show-overflow-tooltip />
<el-table-column label="工时" prop="originalHours" align="center" />
</el-table>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitGenerateSummary" :loading="buttonLoading" :disabled="!summaryPreviewData"> </el-button>
<el-button @click="generateDialog.visible = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@ -113,8 +167,12 @@ import { getUserList, listUser } from '@/api/system/user';
import { UserQuery, UserVO } from '@/api/system/user/types';
import { allListDept, listDept } from '@/api/system/dept';
import { DeptVO } from '@/api/system/dept/types';
import { generateTimesheetSummary, addTimesheetSummary as submitSummaryApi } from '@/api/oa/erp/timesheetSummary';
import { TimesheetSummaryVO } from '@/api/oa/erp/timesheetSummary/types';
import { useUserStore } from '@/store/modules/user';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const { flow_status, timesheet_status } = toRefs<any>(proxy?.useDict('flow_status', 'timesheet_status'));
@ -329,4 +387,85 @@ onMounted(async () => {
//
getList();
});
//
const generateDialog = reactive({
visible: false,
title: '生成月汇总工时'
});
const generateFormRef = ref<ElFormInstance>();
const generateLoading = ref(false);
const summaryPreviewData = ref<TimesheetSummaryVO | null>(null);
const generateForm = reactive({
monthCode: '',
deptId: userStore.deptId
});
const generateRules = {
monthCode: [{ required: true, message: '请选择月份', trigger: 'change' }],
deptId: [{ required: true, message: '请选择部门', trigger: 'change' }]
};
const handleGenerateSummary = () => {
generateForm.monthCode = '';
generateForm.deptId = userStore.deptId;
summaryPreviewData.value = null;
generateDialog.visible = true;
};
const handleGeneratePreview = () => {
generateFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
generateLoading.value = true;
try {
const res = await generateTimesheetSummary({
monthCode: generateForm.monthCode,
deptId: generateForm.deptId
});
summaryPreviewData.value = res.data;
} finally {
generateLoading.value = false;
}
}
});
};
const calculateTotals = () => {
if (!summaryPreviewData.value || !summaryPreviewData.value.summaryDetailList) return;
let totalProject = 0;
let totalDept = 0;
summaryPreviewData.value.summaryDetailList.forEach((item) => {
const hours = Number(item.adjustedHours) || 0;
if (item.isProject === '1') {
totalProject += hours;
} else {
totalDept += hours;
}
});
summaryPreviewData.value.totalProjectHours = totalProject;
summaryPreviewData.value.totalDeptHours = totalDept;
summaryPreviewData.value.totalHours = totalProject + totalDept;
};
const submitGenerateSummary = async () => {
if (!summaryPreviewData.value) return;
buttonLoading.value = true;
try {
//
const submitData = {
...summaryPreviewData.value,
summaryDetailList: summaryPreviewData.value.summaryDetailList
};
await submitSummaryApi(submitData as any);
proxy?.$modal.msgSuccess('生成月汇总工时成功');
generateDialog.visible = false;
} finally {
buttonLoading.value = false;
}
};
</script>

@ -4,11 +4,18 @@
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
<el-form-item label="月份编码" prop="monthCode">
<el-input v-model="queryParams.monthCode" placeholder="请输入月份编码(如: 202604)" clearable @keyup.enter="handleQuery" />
</el-form-item>
<!-- <el-form-item label="月份编码" prop="monthCode">
<el-input v-model="queryParams.monthCode" placeholder="选择月份后自动填充" clearable @keyup.enter="handleQuery" />
</el-form-item> -->
<el-form-item label="月份" prop="monthLabel">
<el-input v-model="queryParams.monthLabel" placeholder="请输入月份显示名(如: 2026年4月)" clearable @keyup.enter="handleQuery" />
<el-date-picker
v-model="queryParams.monthLabel"
type="month"
value-format="YYYY年M月"
placeholder="请选择月份"
clearable
@change="handleQuery"
/>
</el-form-item>
<el-form-item label="起始日期" prop="startDate">
<el-date-picker clearable v-model="queryParams.startDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择起始日期" />
@ -105,18 +112,24 @@
<!-- 添加或修改月标准工时信息对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="timesheetStandardMonthFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="月份编码" prop="monthCode">
<el-input v-model="form.monthCode" placeholder="请输入月份编码(YYYYMM如202604)" />
</el-form-item>
<el-form-item label="月份显示名" prop="monthLabel">
<el-input v-model="form.monthLabel" placeholder="请输入月份显示名(如2026年4月)" />
<!-- <el-form-item label="月份编码" prop="monthCode">
<el-input v-model="form.monthCode" placeholder="选择月份后自动填充" />
</el-form-item> -->
<el-form-item label="月份" prop="monthLabel">
<el-date-picker
v-model="form.monthLabel"
type="month"
value-format="YYYY年M月"
placeholder="请选择月份"
style="width: 100%"
@change="handleMonthChange"
/>
</el-form-item>
<el-form-item label="起始日期" prop="startDate">
<el-date-picker clearable v-model="form.startDate" type="datetime" value-format="YYYY-MM-DD " placeholder="请选择起始日期">
</el-date-picker>
<el-date-picker clearable v-model="form.startDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择起始日期" style="width: 100%" />
</el-form-item>
<el-form-item label="截止日期" prop="endDate">
<el-date-picker clearable v-model="form.endDate" type="datetime" value-format="YYYY-MM-DD " placeholder="请选择截止日期"> </el-date-picker>
<el-date-picker clearable v-model="form.endDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择截止日期" style="width: 100%" />
</el-form-item>
<el-form-item label="月标准工时天数" prop="standardDays">
<el-input v-model="form.standardDays" placeholder="请输入月标准工时天数" />
@ -241,6 +254,19 @@ const handleQuery = () => {
getList();
};
/** 月份选择变更逻辑 */
const handleMonthChange = (val: string) => {
if (!val) return;
// YYYYM
const match = val.match(/(\d{4})年(\d{1,2})月/);
if (match) {
const year = parseInt(match[1]);
const month = parseInt(match[2]);
// YYYYMM
form.value.monthCode = `${year}${month.toString().padStart(2, '0')}`;
}
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();

@ -7,14 +7,20 @@
<el-form-item label="汇总编号" prop="summaryCode">
<el-input v-model="queryParams.summaryCode" placeholder="请输入汇总编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="月份编码" prop="monthCode">
<el-input v-model="queryParams.monthCode" placeholder="请输入月份编码(YYYYMM)" clearable @keyup.enter="handleQuery" />
<el-form-item label="月份" prop="monthCode">
<el-date-picker
v-model="queryParams.monthCode"
type="month"
value-format="YYYYMM"
placeholder="请选择月份"
clearable
@change="handleQuery"
/>
</el-form-item>
<el-form-item label="部门ID" prop="deptId">
<el-input v-model="queryParams.deptId" placeholder="请输入部门ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="部门负责人ID" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入部门负责人ID" clearable @keyup.enter="handleQuery" />
<el-form-item label="部门" prop="deptId">
<el-select v-model="queryParams.deptId" placeholder="请选择部门" clearable filterable style="width: 200px" @change="handleQuery">
<el-option v-for="dept in deptList" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
</el-select>
</el-form-item>
<el-form-item label="月标准工时" prop="standardDays">
<el-input v-model="queryParams.standardDays" placeholder="请输入月标准工时天数" clearable @keyup.enter="handleQuery" />
@ -31,14 +37,14 @@
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<!-- <el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['oa/erp:timesheetSummary:add']"></el-button>
</el-col>
<el-col :span="1.5">
</el-col> -->
<!-- <el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['oa/erp:timesheetSummary:edit']"
>修改</el-button
>
</el-col>
</el-col> -->
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['oa/erp:timesheetSummary:remove']"
>删除</el-button
@ -56,8 +62,8 @@
<el-table-column label="汇总工时ID" align="center" prop="summaryId" v-if="columns[0].visible" />
<el-table-column label="汇总编号" align="center" prop="summaryCode" v-if="columns[2].visible" />
<el-table-column label="月份编码" align="center" prop="monthCode" v-if="columns[3].visible" />
<el-table-column label="部门ID" align="center" prop="deptId" v-if="columns[4].visible" />
<el-table-column label="部门负责人ID" align="center" prop="userId" v-if="columns[5].visible" />
<el-table-column label="部门" align="center" prop="deptName" v-if="columns[4].visible" />
<el-table-column label="部门负责人" align="center" prop="leaderName" v-if="columns[5].visible" />
<el-table-column label="关联月标准工时ID" align="center" prop="standardMonthId" v-if="columns[6].visible" />
<el-table-column label="月标准工时" align="center" prop="standardDays" v-if="columns[7].visible" />
<el-table-column label="项目工时合计" align="center" prop="totalProjectHours" v-if="columns[8].visible" />
@ -67,8 +73,14 @@
<el-table-column label="备注" align="center" prop="remark" v-if="columns[12].visible" />
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['oa/erp:timesheetSummary:edit']"></el-button>
<el-tooltip content="调整明细" placement="top">
<el-button
link
type="success"
icon="Operation"
@click="handleAdjust(scope.row)"
v-hasPermi="['oa/erp:timesheetSummary:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
@ -85,6 +97,79 @@
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 调整汇总工时对话框 -->
<el-dialog :title="adjustDialog.title" v-model="adjustDialog.visible" width="1000px" append-to-body>
<div v-if="adjustData" class="mt-4">
<el-descriptions title="汇总统计" :column="4" border class="mb-4">
<el-descriptions-item label="项目总工时">{{ adjustData.totalProjectHours }}</el-descriptions-item>
<el-descriptions-item label="部门总工时">{{ adjustData.totalDeptHours }}</el-descriptions-item>
<el-descriptions-item label="总工时">{{ adjustData.totalHours }}</el-descriptions-item>
<el-descriptions-item label="总人数">{{ adjustData.staffCount }}</el-descriptions-item>
<el-descriptions-item label="标准天数">{{ adjustData.standardDays }}</el-descriptions-item>
</el-descriptions>
<div class="mb-4 flex items-center">
<span class="mr-2 text-sm font-medium">人员搜索:</span>
<el-input v-model="staffSearchName" placeholder="输入姓名搜索..." clearable style="width: 250px" prefix-icon="Search" />
</div>
<el-table :data="filteredDetailList" border max-height="400">
<el-table-column label="序号" type="index" width="55" align="center" />
<el-table-column label="人员" prop="staffName" align="center" />
<el-table-column label="类型" align="center">
<template #default="scope">
<el-tag :type="scope.row.isProject === '1' ? 'success' : 'info'">
{{ scope.row.isProject === '1' ? '项目' : '部门' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="原始项目" prop="originalProjectName" align="center" show-overflow-tooltip />
<el-table-column label="原始工时" prop="originalHours" align="center" />
<el-table-column label="调整项目" align="center" width="200">
<template #default="scope">
<el-select
v-model="scope.row.adjustedProjectId"
filterable
clearable
placeholder="请选择项目"
v-if="scope.row.isProject === '1'"
@change="(val) => handleProjectChange(val, scope.row)"
>
<el-option v-for="item in projectList" :key="item.projectId" :label="item.projectName" :value="item.projectId" />
</el-select>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="调整工时" align="center" width="150">
<template #default="scope">
<el-input-number
v-model="scope.row.adjustedHours"
:precision="1"
:step="0.5"
:min="0"
size="small"
style="width: 100%"
@change="calculateTotals"
/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="scope">
<el-button link type="primary" icon="Plus" @click="handleAddRow(scope.row)" v-if="scope.row.isProject === '1'"></el-button>
<el-button link type="danger" icon="Minus" @click="handleRemoveRow(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitAdjust" :loading="buttonLoading"> </el-button>
<el-button @click="adjustDialog.visible = false"> </el-button>
</div>
</template>
</el-dialog>
<!-- 添加或修改月汇总工时信息对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="timesheetSummaryFormRef" :model="form" :rules="rules" label-width="120px">
@ -141,6 +226,8 @@ import {
updateTimesheetSummary
} from '@/api/oa/erp/timesheetSummary';
import { TimesheetSummaryVO, TimesheetSummaryQuery, TimesheetSummaryForm } from '@/api/oa/erp/timesheetSummary/types';
import { getErpProjectInfoList } from '@/api/oa/erp/projectInfo';
import { allListDept } from '@/api/system/dept';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -161,6 +248,14 @@ const dialog = reactive<DialogOption>({
title: ''
});
const deptList = ref<any[]>([]);
/** 查询部门列表 */
const getDeptList = async () => {
const res = await allListDept({ deptCategory: '03' } as any);
deptList.value = res.data;
};
//
const columns = ref<FieldOption[]>([
{ key: 0, label: `汇总工时ID`, visible: false },
@ -321,6 +416,148 @@ const handleExport = () => {
};
onMounted(() => {
getDeptList();
getList();
});
//
const adjustDialog = reactive({
visible: false,
title: '调整汇总工时明细'
});
const adjustData = ref<TimesheetSummaryVO | null>(null);
const projectList = ref<any[]>([]);
const staffSearchName = ref('');
const filteredDetailList = computed(() => {
if (!adjustData.value || !adjustData.value.summaryDetailList) return [];
if (!staffSearchName.value) return adjustData.value.summaryDetailList;
return adjustData.value.summaryDetailList.filter(
(item) => item.staffName && item.staffName.toLowerCase().includes(staffSearchName.value.toLowerCase())
);
});
const loadProjectList = async () => {
if (projectList.value.length === 0) {
const res = await getErpProjectInfoList({});
projectList.value = res.data.map((p: any) => ({
...p,
projectId: String(p.projectId)
}));
}
};
const handleAdjust = async (row: TimesheetSummaryVO) => {
const summaryId = row.summaryId;
const res = await getTimesheetSummary(summaryId);
adjustData.value = res.data;
staffSearchName.value = '';
await loadProjectList();
// ID
if (adjustData.value?.summaryDetailList) {
adjustData.value.summaryDetailList.forEach((detail) => {
if (detail.adjustedProjectId) {
detail.adjustedProjectId = String(detail.adjustedProjectId);
}
if (detail.originalProjectId) {
detail.originalProjectId = String(detail.originalProjectId);
}
if (detail.isProject === '1' && !detail.adjustedProjectId && detail.originalProjectId) {
detail.adjustedProjectId = detail.originalProjectId;
detail.adjustedProjectName = detail.originalProjectName;
detail.adjustedProjectCode = detail.originalProjectCode;
}
// ID el-select ID
if (detail.isProject === '1' && detail.adjustedProjectId) {
const pId = String(detail.adjustedProjectId);
const isExist = projectList.value.some((p) => String(p.projectId) === pId);
if (!isExist) {
projectList.value.push({
projectId: pId,
projectName: detail.adjustedProjectName || detail.originalProjectName || pId,
projectCode: detail.adjustedProjectCode || detail.originalProjectCode
});
}
}
});
}
adjustDialog.visible = true;
};
const handleProjectChange = (val: string | number, row: any) => {
const project = projectList.value.find((p) => String(p.projectId) === String(val));
if (project) {
row.adjustedProjectName = project.projectName;
row.adjustedProjectCode = project.projectCode;
} else {
row.adjustedProjectName = undefined;
row.adjustedProjectCode = undefined;
}
};
const handleAddRow = (row: any) => {
if (!adjustData.value || !adjustData.value.summaryDetailList) return;
const index = adjustData.value.summaryDetailList.indexOf(row);
if (index === -1) return;
const newRow = { ...row };
newRow.summaryDetailId = undefined; //
newRow.isGenerated = '0'; // 0
//
newRow.adjustedHours = 0;
newRow.adjustedProjectId = undefined;
newRow.adjustedProjectName = undefined;
newRow.adjustedProjectCode = undefined;
adjustData.value.summaryDetailList.splice(index + 1, 0, newRow);
calculateTotals();
};
const handleRemoveRow = (row: any) => {
if (!adjustData.value || !adjustData.value.summaryDetailList) return;
const index = adjustData.value.summaryDetailList.indexOf(row);
if (index === -1) return;
adjustData.value.summaryDetailList.splice(index, 1);
calculateTotals();
};
const calculateTotals = () => {
if (!adjustData.value || !adjustData.value.summaryDetailList) return;
let totalProject = 0;
let totalDept = 0;
adjustData.value.summaryDetailList.forEach((item) => {
const hours = Number(item.adjustedHours) || 0;
if (item.isProject === '1') {
totalProject += hours;
} else {
totalDept += hours;
}
});
adjustData.value.totalProjectHours = totalProject;
adjustData.value.totalDeptHours = totalDept;
adjustData.value.totalHours = totalProject + totalDept;
};
const submitAdjust = async () => {
if (!adjustData.value) return;
buttonLoading.value = true;
try {
await updateTimesheetSummary(adjustData.value as any);
proxy?.$modal.msgSuccess('调整成功');
adjustDialog.visible = false;
await getList();
} finally {
buttonLoading.value = false;
}
};
</script>

Loading…
Cancel
Save