2024-10-15 09:53:49 +00:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="project-progress-container">
|
|
|
|
|
|
<!-- 左侧项目信息表单 -->
|
|
|
|
|
|
<div class="left-section">
|
|
|
|
|
|
<h2 class="mb20 ml10 textC">项目人员表</h2>
|
|
|
|
|
|
<el-form
|
|
|
|
|
|
:model="projectInfo"
|
|
|
|
|
|
label-width="120px"
|
|
|
|
|
|
class="project-info-form"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-form-item label="选择项目">
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
v-model="selectedProject"
|
|
|
|
|
|
placeholder="请选择项目"
|
|
|
|
|
|
@change="handleProjectChange"
|
2024-10-15 09:59:24 +00:00
|
|
|
|
filterable
|
2024-10-15 09:53:49 +00:00
|
|
|
|
>
|
|
|
|
|
|
<el-option
|
|
|
|
|
|
v-for="project in projectList"
|
|
|
|
|
|
:key="project.projectId"
|
|
|
|
|
|
:label="project.projectName"
|
|
|
|
|
|
:value="project.projectId"
|
|
|
|
|
|
></el-option>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="项目名称">
|
|
|
|
|
|
<span>{{ projectInfo.projectName }}</span>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="项目编码">
|
|
|
|
|
|
<span>{{ projectInfo.projectCode }}</span>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="预计工时">
|
|
|
|
|
|
<span>{{ projectInfo.budgetDate }} 天</span>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="项目开始时间">
|
|
|
|
|
|
<span>{{ projectInfo.startDate }}</span>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="项目结束时间">
|
|
|
|
|
|
<span>{{ projectInfo.endDate }}</span>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧滚动列表格 -->
|
|
|
|
|
|
<div class="right-section">
|
|
|
|
|
|
<div class="date-range-container mb20">
|
|
|
|
|
|
<span class="date-range-label">统计时间:</span>
|
|
|
|
|
|
<el-date-picker
|
|
|
|
|
|
v-model="dateRange"
|
|
|
|
|
|
type="daterange"
|
|
|
|
|
|
range-separator="至"
|
|
|
|
|
|
start-placeholder="开始日期"
|
|
|
|
|
|
end-placeholder="结束日期"
|
|
|
|
|
|
@change="handleDateRangeChange"
|
|
|
|
|
|
format="yyyy-MM-dd"
|
|
|
|
|
|
value-format="yyyy-MM-dd"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<CustomTable
|
|
|
|
|
|
:columns="scrollableColumns"
|
|
|
|
|
|
:tableData="executionData"
|
|
|
|
|
|
:showPagination="false"
|
|
|
|
|
|
></CustomTable>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import CustomTable from "@/components/CustomTable.vue";
|
|
|
|
|
|
import { projectBank, projectApi } from "@/utils/api";
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
components: {
|
|
|
|
|
|
CustomTable,
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
timeRange: [],
|
|
|
|
|
|
dateRange: this.getDefaultDateRange(),
|
|
|
|
|
|
selectedProject: null,
|
|
|
|
|
|
projectInfo: {
|
|
|
|
|
|
projectName: "",
|
|
|
|
|
|
projectCode: "",
|
|
|
|
|
|
budgetDate: "",
|
|
|
|
|
|
startDate: "",
|
|
|
|
|
|
endDate: "",
|
|
|
|
|
|
},
|
|
|
|
|
|
projectList: [],
|
|
|
|
|
|
scrollableColumns: [],
|
|
|
|
|
|
executionData: [],
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
getDefaultDateRange() {
|
|
|
|
|
|
const startOfMonth = this.moment().startOf("month").format("YYYY-MM-DD");
|
|
|
|
|
|
const endOfMonth = this.moment().endOf("month").format("YYYY-MM-DD");
|
|
|
|
|
|
this.timeRange = [startOfMonth, endOfMonth];
|
|
|
|
|
|
return [startOfMonth, endOfMonth];
|
|
|
|
|
|
},
|
|
|
|
|
|
handleDateRangeChange() {
|
|
|
|
|
|
this.timeRange = [
|
|
|
|
|
|
this.dateRange[0] + " 00:00:00",
|
|
|
|
|
|
this.dateRange[1] + " 23:59:59",
|
|
|
|
|
|
];
|
|
|
|
|
|
this.getProjectUser();
|
|
|
|
|
|
},
|
|
|
|
|
|
async getProjectList() {
|
|
|
|
|
|
const res = await projectBank.porjectProgress({
|
|
|
|
|
|
startDate: this.dateRange[0] + " 00:00:00",
|
|
|
|
|
|
endDate: this.dateRange[1] + " 23:59:59",
|
|
|
|
|
|
});
|
|
|
|
|
|
this.projectList = res.data.map((ele) => ({
|
|
|
|
|
|
projectName: ele.projectName,
|
|
|
|
|
|
projectId: ele.projectId,
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
if (this.projectList.length) {
|
|
|
|
|
|
if (this.$route.query.projectId) {
|
|
|
|
|
|
this.dateRange = [
|
|
|
|
|
|
this.$route.query.startDate,
|
|
|
|
|
|
this.$route.query.endDate,
|
|
|
|
|
|
];
|
|
|
|
|
|
this.validateDateRange();
|
|
|
|
|
|
this.selectedProject = Number(this.$route.query.projectId);
|
|
|
|
|
|
this.handleProjectChange(this.$route.query.projectId, 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.selectedProject = this.projectList[0].projectId;
|
|
|
|
|
|
this.handleProjectChange(this.projectList[0].projectId);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
validateDateRange() {
|
|
|
|
|
|
const startDate = new Date(this.dateRange[0]);
|
|
|
|
|
|
const endDate = new Date(this.dateRange[1]);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算日期范围的差值(以毫秒为单位)
|
|
|
|
|
|
const timeDiff = endDate - startDate;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算三个月的毫秒数
|
|
|
|
|
|
const threeMonthsInMs = 3 * 30 * 24 * 60 * 60 * 1000; // 约为三个月
|
|
|
|
|
|
|
|
|
|
|
|
// 检查日期范围是否超过三个月
|
|
|
|
|
|
if (timeDiff > threeMonthsInMs) {
|
|
|
|
|
|
// 如果超过三个月,将结束日期设置为开始日期加三个月
|
|
|
|
|
|
const newEndDate = new Date(startDate);
|
|
|
|
|
|
newEndDate.setMonth(startDate.getMonth() + 3);
|
|
|
|
|
|
this.dateRange[1] = newEndDate.toISOString().split("T")[0]; // 格式化为 YYYY-MM-DD
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
async handleProjectChange(projectId, time) {
|
|
|
|
|
|
const res = await projectApi.getProjectDetail(projectId);
|
|
|
|
|
|
this.projectInfo = res.data;
|
|
|
|
|
|
if (!time)
|
|
|
|
|
|
this.dateRange = [
|
|
|
|
|
|
this.projectInfo.startDate.split(" ")[0],
|
|
|
|
|
|
this.projectInfo.endDate.split(" ")[0],
|
|
|
|
|
|
];
|
|
|
|
|
|
this.validateDateRange();
|
|
|
|
|
|
this.handleDateRangeChange();
|
|
|
|
|
|
},
|
|
|
|
|
|
async getProjectUser() {
|
|
|
|
|
|
const res = await projectBank.projectUser({
|
|
|
|
|
|
startDate: this.dateRange[0] + " 00:00:00",
|
|
|
|
|
|
endDate: this.dateRange[1] + " 23:59:59",
|
|
|
|
|
|
projectId: this.projectInfo.projectId,
|
|
|
|
|
|
});
|
|
|
|
|
|
console.log(123,this.dateRange);
|
|
|
|
|
|
|
|
|
|
|
|
const start = new Date(this.timeRange[0]);
|
|
|
|
|
|
const end = new Date(this.timeRange[1]);
|
|
|
|
|
|
let index = 0;
|
|
|
|
|
|
this.executionData = [{}];
|
|
|
|
|
|
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
|
|
|
|
|
|
const dateStr = `${d.getMonth() + 1}/${d.getDate()}`;
|
|
|
|
|
|
index++;
|
|
|
|
|
|
this.executionData[0][dateStr] = res.data.detailList[index - 1];
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
goToDetail(row) {
|
|
|
|
|
|
this.$router.push({
|
|
|
|
|
|
path: "/",
|
|
|
|
|
|
query: { userId: row.userId, projectId: this.projectInfo.projectId,nickName:row.userName },
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
timeRange: {
|
|
|
|
|
|
deep: true,
|
|
|
|
|
|
handler(newVal) {
|
|
|
|
|
|
const days = [];
|
|
|
|
|
|
if (newVal && newVal.length === 2) {
|
|
|
|
|
|
const start = new Date(this.timeRange[0]);
|
|
|
|
|
|
const end = new Date(this.timeRange[1]);
|
|
|
|
|
|
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
|
|
|
|
|
|
const dayOfWeek = [
|
|
|
|
|
|
"周日",
|
|
|
|
|
|
"周一",
|
|
|
|
|
|
"周二",
|
|
|
|
|
|
"周三",
|
|
|
|
|
|
"周四",
|
|
|
|
|
|
"周五",
|
|
|
|
|
|
"周六",
|
|
|
|
|
|
][d.getDay()];
|
|
|
|
|
|
const dateStr = `${d.getMonth() + 1}/${d.getDate()}`;
|
|
|
|
|
|
days.push({
|
|
|
|
|
|
prop: dateStr,
|
|
|
|
|
|
label: `${dayOfWeek}\n${dateStr}`,
|
|
|
|
|
|
minWidth: 100,
|
|
|
|
|
|
type: "multiButton",
|
|
|
|
|
|
callback: (data, row) => {
|
|
|
|
|
|
return data.userName + `(${data.workTime}天)`;
|
|
|
|
|
|
},
|
|
|
|
|
|
Event: (data, row) => {
|
|
|
|
|
|
if (data) {
|
|
|
|
|
|
this.goToDetail(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
this.scrollableColumns = days;
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
|
|
|
this.getProjectList();
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.project-progress-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
height: 88vh;
|
|
|
|
|
|
background-color: white;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.left-section,
|
|
|
|
|
|
.right-section {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.left-section {
|
|
|
|
|
|
width: 400px; /* 根据固定列的总宽度调整 */
|
|
|
|
|
|
padding-top: 34px;
|
|
|
|
|
|
padding-bottom: 20px;
|
|
|
|
|
|
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.5); /* 添加右侧阴影 */
|
|
|
|
|
|
z-index: 1; /* 确保左侧在右侧之上 */
|
|
|
|
|
|
margin-right: 5px;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.right-section {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
padding-left: 0; /* 移除左侧内边距,与左侧部分紧密相连 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.date-range-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 500px;
|
|
|
|
|
|
margin-left: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.date-range-label {
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-table {
|
|
|
|
|
|
height: 100% !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-table__header th {
|
|
|
|
|
|
background-color: #4a4a4a;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-table__body td {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-table__footer td {
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
text-align: center; /* 确保合计行内容居中 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-table__header .cell,
|
|
|
|
|
|
::v-deep .el-table__body .cell,
|
|
|
|
|
|
::v-deep .el-table__footer .cell {
|
|
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
padding: 8px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-table__body-wrapper {
|
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
// height: 88%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 确保两个表格的高度一致 */
|
|
|
|
|
|
.left-section ::v-deep .el-table,
|
|
|
|
|
|
.right-section ::v-deep .el-table {
|
|
|
|
|
|
height: 100% !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 调整日期选择器样式 */
|
|
|
|
|
|
::v-deep .el-date-editor {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 调整表格内容的字体大小 */
|
|
|
|
|
|
::v-deep .el-table {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 调整表头的样式 */
|
|
|
|
|
|
::v-deep .el-table__header-wrapper {
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-table__header th {
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 调整合计行的样式 */
|
|
|
|
|
|
::v-deep .el-table__footer-wrapper {
|
|
|
|
|
|
background-color: #606266;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-table__footer td {
|
|
|
|
|
|
background-color: #f5f7fa !important;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.project-name {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.project-name:hover {
|
|
|
|
|
|
text-decoration: underline;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-select-container {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 25px;
|
|
|
|
|
|
right: 10px;
|
|
|
|
|
|
width: 220px;
|
|
|
|
|
|
z-index: 2;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
span {
|
|
|
|
|
|
width: 100px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|