From d6236c06b6236dac31c284729e0f8f271a03d451 Mon Sep 17 00:00:00 2001 From: Yangk Date: Wed, 6 May 2026 17:55:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(oa/erp):=20=E6=B7=BB=E5=8A=A0=E6=9C=88?= =?UTF-8?q?=E6=B1=87=E6=80=BB=E5=B7=A5=E6=97=B6=E7=94=9F=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 timesheetSummary API 中新增 generateTimesheetSummary 接口用于生成月汇总预览 - 在 timesheetInfo 页面添加生成月汇总工时按钮和对话框界面 - 实现月汇总工时预览功能,包括汇总统计和明细表格展示 - 添加汇总数据提交功能,支持将预览数据保存为正式汇总记录 - 在 timesheetStandardMonth 页面优化月份选择组件,使用日期选择器替代文本输入 - 在 timesheetSummary 页面添加明细调整功能,支持项目和工时调整 - 更新相关类型定义文件以支持新的汇总功能字段结构 --- src/api/oa/erp/timesheetSummary/index.ts | 24 +- src/api/oa/erp/timesheetSummary/types.ts | 22 ++ src/store/modules/user.ts | 3 + src/views/oa/erp/timesheetInfo/index.vue | 151 +++++++++- .../oa/erp/timesheetStandardMonth/index.vue | 50 +++- src/views/oa/erp/timesheetSummary/index.vue | 267 +++++++++++++++++- 6 files changed, 478 insertions(+), 39 deletions(-) diff --git a/src/api/oa/erp/timesheetSummary/index.ts b/src/api/oa/erp/timesheetSummary/index.ts index 7f7077e..77bfd4b 100644 --- a/src/api/oa/erp/timesheetSummary/index.ts +++ b/src/api/oa/erp/timesheetSummary/index.ts @@ -67,10 +67,22 @@ export const delTimesheetSummary = (summaryId: string | number | Array => { + return request({ + url: '/oa/erp/timesheetSummary/generate', + method: 'post', + data: query + }); }; diff --git a/src/api/oa/erp/timesheetSummary/types.ts b/src/api/oa/erp/timesheetSummary/types.ts index 1a8124e..fd2238d 100644 --- a/src/api/oa/erp/timesheetSummary/types.ts +++ b/src/api/oa/erp/timesheetSummary/types.ts @@ -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 { diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index b714d03..4a83fa2 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -11,6 +11,7 @@ export const useUserStore = defineStore('user', () => { const name = ref(''); const nickname = ref(''); const userId = ref(''); + const deptId = ref(''); const tenantId = ref(''); const avatar = ref(''); const roles = ref>([]); // 用户角色编码集合 → 判断路由权限 @@ -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, diff --git a/src/views/oa/erp/timesheetInfo/index.vue b/src/views/oa/erp/timesheetInfo/index.vue index e95a71c..fc150f4 100644 --- a/src/views/oa/erp/timesheetInfo/index.vue +++ b/src/views/oa/erp/timesheetInfo/index.vue @@ -14,12 +14,12 @@ - - - - - - + + + + + + @@ -53,6 +53,11 @@ 导出 + + 生成月汇总工时 + @@ -103,6 +108,55 @@ + + + + + + + + + + + + + + 汇总 + + + + +
+ + {{ summaryPreviewData.totalProjectHours }} + {{ summaryPreviewData.totalDeptHours }} + {{ summaryPreviewData.totalHours }} + {{ summaryPreviewData.staffCount }} + {{ summaryPreviewData.standardDays }} + + + + + + + + + + + +
+ + +
@@ -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(proxy?.useDict('flow_status', 'timesheet_status')); @@ -329,4 +387,85 @@ onMounted(async () => { // 加载数据列表 getList(); }); + +// 生成汇总弹窗数据 +const generateDialog = reactive({ + visible: false, + title: '生成月汇总工时' +}); +const generateFormRef = ref(); +const generateLoading = ref(false); +const summaryPreviewData = ref(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; + } +}; diff --git a/src/views/oa/erp/timesheetStandardMonth/index.vue b/src/views/oa/erp/timesheetStandardMonth/index.vue index ce6d002..3618413 100644 --- a/src/views/oa/erp/timesheetStandardMonth/index.vue +++ b/src/views/oa/erp/timesheetStandardMonth/index.vue @@ -4,11 +4,18 @@
- - - + - + @@ -105,18 +112,24 @@ - - - - - + + + - - + - + @@ -241,6 +254,19 @@ const handleQuery = () => { getList(); }; +/** 月份选择变更逻辑 */ +const handleMonthChange = (val: string) => { + if (!val) return; + // 解析 YYYY年M月 + 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(); diff --git a/src/views/oa/erp/timesheetSummary/index.vue b/src/views/oa/erp/timesheetSummary/index.vue index 01b1721..f45d40a 100644 --- a/src/views/oa/erp/timesheetSummary/index.vue +++ b/src/views/oa/erp/timesheetSummary/index.vue @@ -7,14 +7,20 @@ - - + + - - - - - + + + + @@ -31,14 +37,14 @@