Project2013工时计算出现小数问题解决方案

在使用Project2013安排项目工作计划时,可能会遇到工期计算错误的问题,如固定工期与实际不符或者工期显示为小数。本文详细解释了这些问题产生的原因,并提供了解决方案。
问题现象:使用Project 2013安排项目工作计划时,会出现两个情况:1)当你设置了固定工期为2天,设置了任务的开始日期(比如说)2012-04-01,那么任务的完成日期应该为2012-04-02,但是Project 2013会把该任务的完成变成2012-04-03。2)当你设置了任务的开始时间(比如说)是2012-04-01,完成时间设置为2012-04-02,那么工期按照计算应该为2天,但是却显示1.88天。

为什么会出现这种状况呢?是因为项目工作的标准日历中的工作时间是8:00-17:00,而默认的工作时间是9:00-18:00,这两者之间不匹配导致的计算工期出现小数的问题。

解决办法:打开Project 2013的文件->选项对话框,在左边导航栏选中“日程”,将默认开始时间设置“8:00”,将默认结束时间设置为“17:00”这样就行了。
<template> <basic-container-card> <!-- 基础信息 --> <el-card> <avue-form :option="baseformOption" v-model="baseForm" ref="baseForm" class="eer-avue_form"> <template slot="naturalWeek"> <el-date-picker v-model="baseForm.naturalWeek" type="week" format="yyyy 第 WW 周" :picker-options="{firstDayOfWeek: 1}" :placeholder="$t('weeklyWorkingHourRegistration.weekPlaceholder')" @change="changeWeek"> </el-date-picker> </template> </avue-form> </el-card> <!-- 工时明细 --> <el-card> <el-collapse v-model="workHoursDetailNames" class="eer-collapse"> <el-collapse-item name="1"> <template #title> <i class="el-icon-menu avue-group__icon"/> <h1 class="avue-group__title">{{ $t('tagsView.workHoursDetailInfo') }}</h1> </template> <avue-crud :option="workHoursDetailOption" :data="workHoursDetailData" v-model="workHoursDetailForm" :table-loading="workHoursDetailLoading" @row-save="rowSave" @row-update="rowSave" @selection-change="selectionChange" @refresh-change="refreshChange" ref="workHoursDetailCrud"> <template slot="menuLeft"> <el-button type="primary" size="small" icon="el-icon-plus" v-if="permission.weeklyWorkingHourRegistration_workHourDetailAdd" @click="handleAdd"> {{ $t("menuLeft.addBtn") }} </el-button> <el-button type="primary" size="small" icon="el-icon-delete" v-if="permission.weeklyWorkingHourRegistration_workHourDetailDelete" @click="handleDelete"> {{ $t('menuLeft.deleteBtn') }} </el-button> </template> <template slot="projectMembersForm" slot-scope="{row}"> <el-input v-model="row.projectMembers" :placeholder="$t('weeklyWorkingHourRegistration.projectMembersPlaceholder')" maxlength="200" show-word-limit v-if="row.roles === '11'"/> <el-select v-model="row.projectMembersId" :placeholder="$t('weeklyWorkingHourRegistration.projectMembersIdPlaceholder')" filterable v-else> <el-option v-for="(item, index) in projectMembersData" :key="index" :label="item.realName" :value="item.id"/> </el-select> </template> <template slot-scope="{row}" slot="menu"> <el-button type="text" size="small" icon="el-icon-edit" v-if="permission.weeklyWorkingHourRegistration_workHourDetailEdit && !row.$cellEdit" @click="handleEdit(row)"> {{ $t("menuLeft.editBtn") }} </el-button> </template> </avue-crud> </el-collapse-item> </el-collapse> </el-card> <!-- 工时汇总 --> <el-card> <el-collapse v-model="workHoursTotalNames" class="eer-collapse"> <el-collapse-item name="1"> <template #title> <i class="el-icon-menu avue-group__icon"/> <h1 class="avue-group__title">{{ $t('tagsView.workHoursTotalInfo') }}</h1> </template> <avue-crud :option="workHoursTotalOption" :data="workHoursTotalData" v-model="workHoursTotalForm" ref="workHoursTotalCrud"> </avue-crud> </el-collapse-item> </el-collapse> <div class="eer-page__footer"> <el-button size="small" type="primary" icon="el-icon-circle-plus-outline" :loading="saveLoading" @click="saveTask('draft')"> {{ $t('menuLeft.saveDraftBtn') }} </el-button> <el-button size="small" type="primary" icon="el-icon-circle-plus-outline" :loading="saveLoading" @click="saveTask('submit')"> {{ $t('menuLeft.submit') }} </el-button> <el-button size="small" icon="el-icon-circle-close" @click="cancelTask"> {{ $t('menuLeft.cancel') }} </el-button> </div> </el-card> </basic-container-card> </template> <script> import i18n from "@/lang"; import { dateColumnOption, dictBizUrl, formOption, labelWidth130, limitColumnOption, numberColumnOption, requiredRule, selectColumnOption, span24, span6, tableColumnOption, tableOption, textareaColumnOption } from "@/util/configuration"; import {mapGetters} from "vuex"; import {getWeekByDate, getWeekRange, translateDate} from "@/util/date"; import { getProjectPhaseDataList, addDataList, deleteWorkHourDetailDataList, addWorkHourDetailDataList, getWorkHourDetailDataList, getDetailInfo } from "@/api/projectMetricsManagement/weeklyWorkingHourRegistration"; import {getUserRoleList} from "@/api/financeManagement/expenseManagement/employeeDailyReimbursementApplication"; export default { data() { return { // 基础信息 baseForm: {}, baseformOption: { ...formOption, ...labelWidth130, group: [{ label: i18n.t('tagsView.baseInfo'), prop: 'baseInfo', icon: 'el-icon-menu', column: [{ label: i18n.t('weeklyWorkingHourRegistration.projectId'), prop: 'projectId', ...span6, ...selectColumnOption, dicUrl: '/api/tmprojectmanagement/page', dicQuery: { current: 1, size: 999999, keywords: '', activeStatus: 2, }, dicFormatter: (res) => { return res.data.records.map(item => { return { label: item.projectName, value: item.id, projectManager: item.projectManager } }) }, props: { label: "label", value: "value" }, filterable: true, disabled: true, rules: [ requiredRule ], change: (value) => { if (value.value) { this.baseForm.projectManagerId = value.item.projectManager; getProjectPhaseDataList({projectId: value.value}).then(res => { this.findObject(this.baseformOption.group[0].column, 'projectPhase').dicData = res.data.data; }).catch(error => { console.error('获取项目阶段数据失败:', error); }); } } }, { label: i18n.t('weeklyWorkingHourRegistration.projectManagerId'), prop: 'projectManagerId', ...span6, ...selectColumnOption, dicData: [], props: { label: "realName", value: "id" }, filterable: true, disabled: true, rules: [ requiredRule ] }, { label: i18n.t('weeklyWorkingHourRegistration.projectPhase'), prop: 'projectPhase', ...span6, ...selectColumnOption, dicData: [], props: { label: "taskName", value: "id" }, filterable: true, rules: [ requiredRule ] }, { label: i18n.t('weeklyWorkingHourRegistration.naturalWeek'), prop: 'naturalWeek', ...span6, rules: [ requiredRule ] }, { label: i18n.t('weeklyWorkingHourRegistration.startAndEndDate'), prop: 'startAndEndDate', ...span6, ...dateColumnOption, type: "daterange", disabled: true, rules: [ requiredRule ] }, { label: i18n.t('weeklyWorkingHourRegistration.actualHour'), prop: 'actualHour', ...span6, disabled: true, rules: [ requiredRule ] }, { label: i18n.t('weeklyWorkingHourRegistration.remark'), prop: 'remark', ...span24, ...textareaColumnOption, }] }] }, // 工时明细 workHoursDetailNames: ['1'], workHoursDetailOption: { ...tableOption, cellBtn: true, column: [{ label: i18n.t("weeklyWorkingHourRegistration.roles"), prop: "roles", ...tableColumnOption, ...selectColumnOption, type: "select", dicUrl: "/api/blade-system/dict-biz/dictionary?code=oa_tt_member_management_role", props: { label: "dictValue", value: "dictKey" }, cell: true, rules: [ requiredRule ] }, { label: i18n.t("weeklyWorkingHourRegistration.projectMembersId"), prop: "projectMembers", ...tableColumnOption, cell: true, }, { label: i18n.t("weeklyWorkingHourRegistration.actualHour"), prop: "actualHour", ...tableColumnOption, ...numberColumnOption, precision: 1, step: '0.1', cell: true, rules: [ requiredRule, { validator: (rule, value, callback) => { if (Number(value) <= 0) { callback(new Error(i18n.t('wcommonMessage.10023'))); } else { callback(); } } } ] }, { label: i18n.t("weeklyWorkingHourRegistration.remark"), prop: "remark", ...tableColumnOption, ...limitColumnOption, cell: true, }] }, workHoursDetailData: [], workHoursDetailForm: {}, workHoursDetailLoading: false, workHoursDetailSelectionList: [], // 工时汇总 workHoursTotalNames: ['1'], workHoursTotalOption: { ...tableOption, menu: false, selection: false, column: [{ label: i18n.t("weeklyWorkingHourRegistration.roles"), prop: "roles", ...tableColumnOption, ...selectColumnOption, dicUrl: dictBizUrl + "oa_tt_member_management_role", }, { label: i18n.t("weeklyWorkingHourRegistration.actualHour"), prop: "actualHour", ...tableColumnOption, ...numberColumnOption, step: '0.1', }] }, workHoursTotalData: [], workHoursTotalForm: {}, projectMembersData: [], batchNo: '', saveLoading: false, // 保存草稿 } }, computed: { ...mapGetters(["permission"]), ids() { return this.workHoursDetailSelectionList.map(ele => ele.id).join(","); } }, mounted() { this.$nextTick(async () => { try { const res = await getUserRoleList(1, 999999, {removeAccount: 'admin'}); this.findObject(this.baseformOption.group[0].column, 'projectManagerId').dicData = res.data.data.records; await this.getDetail(); await this.getProjectMembersData(); } catch (error) { console.error('初始化数据失败:', error); } }); }, methods: { // 切换自然周 changeWeek(value) { if (value) { const weekRange = getWeekRange(value); this.baseForm.startAndEndDate = [weekRange.start, weekRange.end]; } else { this.baseForm.startAndEndDate = []; } }, // 项目成员下拉列表 async getProjectMembersData() { try { const res = await getUserRoleList(1, 999999, {removeAccount: 'admin'}); this.projectMembersData = res.data.data.records; } catch (error) { console.error('获取项目成员数据失败:', error); } }, // 查看数据 async getDetail() { try { this.$nextTick(async () => { const row = JSON.parse(sessionStorage.getItem('weekly-working-hour-registration') || '{}'); if (!row.id) { this.$message.warning(i18n.t('warningMessage.noRecordSelected')); return; } const res = await getDetailInfo({id: row.id}); const data = res.data.data; // 安全地合并数据 this.baseForm = { ...this.baseForm, ...data, startAndEndDate: [] }; // this.batchNo = data.batchNo; // 设置日期范围 if (data.naturalWeek) { const weekRange = getWeekRange(new Date(data.naturalWeek)); this.baseForm.startAndEndDate = [weekRange.start, weekRange.end]; } await this.onLoad(); }); } catch (error) { console.error('获取详情失败:', error); } }, // 多选 selectionChange(list) { this.workHoursDetailSelectionList = [...list]; }, // 清空多选 selectionClear() { this.workHoursDetailSelectionList = []; }, // 刷新 refreshChange() { this.onLoad(); this.selectionClear(); }, async onLoad() { try { const params = { parentId: this.baseForm.id || '', batchNo: this.batchNo || '', // 添加默认值 type: 'edit', }; const res = await getWorkHourDetailDataList(params); // 检查响应状态 if (res.data && res.data.code !== 200) { const errorMsg = res.data.msg || '加载工时明细失败'; throw new Error(errorMsg); } // 确保数据存在 if (!res.data || !res.data.data) { throw new Error('返回数据格式不正确'); } const data = res.data.data.detailList || []; data.forEach(item => { // 确保actualHour是有效数字 const hour = Number(item.actualHour); if (!isNaN(hour)) { item.actualHour = hour.toFixed(1); } else { item.actualHour = '0.0'; } // 确保项目成员字段正确处理 // 如果角色是11并且有projectMembers字段,则保留该字段 // 否则确保projectMembersId字段正确设置 if (item.roles === '11' && item.projectMembers) { // 自定义角色使用projectMembers字段 } else if (item.projectMembersId) { // 从projectMembersData中查找对应的成员名称用于显示 const member = this.projectMembersData.find(m => m.id === item.projectMembersId); if (member) { item.projectMembers = member.realName; } } }); this.workHoursDetailData = data; this.batchNo = res.data.data.batchNo || this.batchNo || ''; this.handleSummary(); } catch (error) { console.error('加载工时明细失败:', error); // 显示更友好的错误提示 let message = '加载工时明细失败,请稍后重试'; if (error.message && error.message !== '加载工时明细失败') { message = error.message; } else if (error.response && error.response.data && error.response.data.msg) { message = error.response.data.msg; } this.$message.error(message); } }, // 工时汇总 handleSummary() { try { // 过滤掉编辑状态的数据 const filteredData = this.workHoursDetailData.filter(item => !item.$cellEdit); // 使用 reduce 计算每个角色的总工时 const totals = filteredData.reduce((acc, item) => { const {roles, actualHour} = item; let amount = Number(actualHour); // 校验数值有效性 if (isNaN(amount) || amount <= 0) { return acc; } // 限制最大值 amount = Math.min(999999.99, amount); // 查找是否已有该角色的项 const existing = acc.find(i => i.roles === roles); if (existing) { // 累加金额并限制最大值 existing.actualHour = Math.min(999999.99, existing.actualHour + amount); } else { // 添加新项 acc.push({ roles, actualHour: amount }); } return acc; }, []); // 保留一位小数 this.workHoursTotalData = totals.map(item => ({ ...item, actualHour: String(item.actualHour.toFixed(1)) })); this.baseFormSummary(); } catch (error) { console.error('计算工时汇总失败:', error); } }, // 基础信息-本周实际工时汇总 baseFormSummary() { try { const total = this.workHoursTotalData.reduce((sum, item) => { const hour = parseFloat(item.actualHour); return sum + (isNaN(hour) ? 0 : hour); }, 0); this.baseForm.actualHour = total.toFixed(1); } catch (error) { console.error('更新基础信息汇总失败:', error); } }, // 工时明细新增 handleAdd() { try { const obj = { $cellEdit: true, roles: null, projectMembers: null, // 确保初始化projectMembers字段 projectMembersId: null, // 确保初始化projectMembersId字段 actualHour: null, remark: null, }; this.workHoursDetailData.unshift({...obj}); } catch (error) { console.error('新增工时明细失败:', error); } }, // 保存 rowSave(row, index, done) { try { // 校验数据 if (!row || typeof row !== 'object') { throw new Error('无效的行数据'); } if (typeof row.actualHour !== 'number' || isNaN(row.actualHour)) { throw new Error('实际工时必须是有效数字'); } // 构造参数,确保正确处理项目成员信息 const params = { ...row, actualHour: parseFloat(row.actualHour.toFixed(1)), batchNo: this.batchNo, }; // 根据角色类型处理项目成员字段 if (row.roles === '11') { // 自定义角色使用projectMembers字段 params.projectMembers = row.projectMembers; // 确保清除projectMembersId字段 delete params.projectMembersId; } else { // 预定义角色使用projectMembersId字段 params.projectMembersId = row.projectMembersId; // 确保清除projectMembers字段 delete params.projectMembers; } addWorkHourDetailDataList(params) .then(() => { this.$message.success(i18n.t("commonMessage.10011")); return this.onLoad(); }) .catch((error) => { console.error('保存工时明细失败:', error); // 显示更具体的错误信息 if (error.response && error.response.data && error.response.data.msg) { this.$message.error(error.response.data.msg); } else { this.$message.error('保存工时明细失败'); } }) .finally(() => { done(); }); } catch (error) { console.error('保存行数据时发生错误:', error); this.$message.error(error.message || '保存工时明细时发生错误'); done(); } }, // 工时明细编辑 handleEdit(row) { try { if (!row || typeof row !== 'object') { throw new Error('无效的行数据'); } this.$set(row, '$cellEdit', true); } catch (error) { console.error('编辑行数据时发生错误:', error); } }, // 工时明细删除 handleDelete() { try { if (this.workHoursDetailSelectionList.length === 0) { this.$message.warning(i18n.t("commonMessage.10001")); return; } this.$confirm(i18n.t("commonMessage.10018"), { confirmButtonText: i18n.t("tips.confirm"), cancelButtonText: i18n.t("tips.cancel"), type: "warning" }).then(async () => { await deleteWorkHourDetailDataList(this.ids); this.$message.success(i18n.t("commonMessage.10011")); await this.onLoad(); }).catch((res) => { if (res.data && res.data.code === 1000) { this.$eermessage.notify({content: res.data.msg}); } this.onLoad(); this.$refs.workHoursDetailCrud.toggleSelection(); this.workHoursDetailSelectionList = []; }); } catch (error) { console.error('删除工时明细失败:', error); } }, // 保存草稿/提交 saveTask(flag) { if (flag === 'submit') { this.$refs.baseForm.validate((valid, done) => { if (valid) { if (this.workHoursDetailData.length === 0) { this.$message.warning(i18n.t('commonMessage.50115')); return false; } this.submitTask(flag); } done(); }); } else { this.submitTask(flag); } }, submitTask(flag) { try { this.saveLoading = true; const weekValue = this.baseForm.naturalWeek ? getWeekByDate(this.baseForm.naturalWeek) : ''; const startDate = this.baseForm.startAndEndDate?.[0] || ''; const endDate = this.baseForm.startAndEndDate?.[1] || ''; const params = { ...this.baseForm, naturalWeek: this.baseForm.naturalWeek ? translateDate(this.baseForm.naturalWeek) : '', naturalWeekValue: weekValue, startTime: startDate, endTime: endDate, summaryList: this.workHoursTotalData, status: flag === 'submit' ? '2' : '1', batchNo: this.batchNo, }; addDataList(params) .then(() => { this.$message.success(i18n.t('commonMessage.10011')); this.cancelTask(); }) .catch((error) => { console.error('提交任务失败:', error); }) .finally(() => { this.saveLoading = false; }); } catch (error) { console.error('提交任务时发生错误:', error); this.saveLoading = false; } }, // 取消 cancelTask() { try { this.$router.$avueRouter.closeTag(); this.$router.push({ path: '/projectMetricsManagement/weeklyWorkingHourRegistration', }); if (this.$refs.baseForm) { this.$refs.baseForm.resetFields(); this.$nextTick(() => { this.$refs.baseForm.clearValidate(); }); } } catch (error) { console.error('取消操作时发生错误:', error); } } } } </script> <style scoped> /* 保持原有样式不变 */ </style> 进入编辑页面,出现如下报错,改正 加载工时明细失败: Error: 请联系管理员查看!(10002) at __webpack_exports__.default (axios.js:176:1)
08-09
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值