2024-10-15 09:53:49 +00:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="project-progress-container">
|
|
|
|
|
|
<!-- 左侧固定列表格 -->
|
|
|
|
|
|
<div class="content flex-col">
|
|
|
|
|
|
<div class="flex-row aic mb20">
|
|
|
|
|
|
<h2 class="textC">人员项目表</h2>
|
|
|
|
|
|
<div class="selectBox flex-row aic">
|
|
|
|
|
|
<span>选择人员</span>
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="selectedUserName"
|
|
|
|
|
|
placeholder="请选择用户"
|
|
|
|
|
|
readonly
|
|
|
|
|
|
@click.native="openUserSelectDialog"
|
|
|
|
|
|
></el-input>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="date-range-container">
|
|
|
|
|
|
<span class="date-range-label">统计时间:</span>
|
|
|
|
|
|
<el-date-picker
|
|
|
|
|
|
v-model="dateRange"
|
|
|
|
|
|
type="daterange"
|
|
|
|
|
|
range-separator="至"
|
|
|
|
|
|
start-placeholder="开始日期"
|
|
|
|
|
|
end-placeholder="结束日期"
|
|
|
|
|
|
format="yyyy-MM-dd"
|
|
|
|
|
|
value-format="yyyy-MM-dd"
|
|
|
|
|
|
:clearable="false"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="f1">
|
|
|
|
|
|
<CustomTable
|
|
|
|
|
|
:columns="fixedColumns"
|
|
|
|
|
|
:tableData="executionData"
|
|
|
|
|
|
:showPagination="false"
|
|
|
|
|
|
:showSummary="true"
|
|
|
|
|
|
:summaryMethod="getFixedColumnsSummaries"
|
2024-10-16 09:32:16 +00:00
|
|
|
|
:tableHeight="600"
|
2024-10-15 09:53:49 +00:00
|
|
|
|
></CustomTable>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 用户选择对话框 -->
|
|
|
|
|
|
<SelectUser
|
|
|
|
|
|
:dialogVisible="userSelectDialogVisible"
|
|
|
|
|
|
:multiSelect="false"
|
|
|
|
|
|
:currentSelectedUser="selectedUser ? [selectedUser] : []"
|
|
|
|
|
|
@confirm="handleUserSelect"
|
|
|
|
|
|
@close="handleUserClose"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import CustomTable from "@/components/CustomTable.vue";
|
|
|
|
|
|
import SelectUser from "@/components/SelectUser.vue";
|
|
|
|
|
|
import { projectBank } from "@/utils/api";
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
components: {
|
|
|
|
|
|
CustomTable,
|
|
|
|
|
|
SelectUser,
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
fixedColumns: [],
|
|
|
|
|
|
executionData: [],
|
|
|
|
|
|
dateRange: [],
|
|
|
|
|
|
selectedUserName: "超级管理员",
|
|
|
|
|
|
selectedUserId: 1,
|
|
|
|
|
|
selectedUser: {
|
|
|
|
|
|
userId: 1,
|
|
|
|
|
|
selectedUserName: "超级管理员",
|
|
|
|
|
|
},
|
|
|
|
|
|
userSelectDialogVisible: false,
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
getDefaultDateRange() {
|
|
|
|
|
|
const startOfMonth = this.moment().startOf("month").format("YYYY-MM-DD");
|
|
|
|
|
|
const endOfMonth = this.moment().endOf("month").format("YYYY-MM-DD");
|
|
|
|
|
|
this.dateRange = [startOfMonth, endOfMonth];
|
|
|
|
|
|
},
|
|
|
|
|
|
openUserSelectDialog() {
|
|
|
|
|
|
this.userSelectDialogVisible = true;
|
|
|
|
|
|
},
|
|
|
|
|
|
async getUserProject() {
|
|
|
|
|
|
const res = await projectBank.porjectProgress({
|
|
|
|
|
|
startDate: this.dateRange[0] + " 00:00:00",
|
|
|
|
|
|
endDate: this.dateRange[1] + " 00:00:00",
|
|
|
|
|
|
userId: this.selectedUserId,
|
|
|
|
|
|
});
|
|
|
|
|
|
this.executionData = res.data;
|
|
|
|
|
|
},
|
|
|
|
|
|
getFixedColumnsSummaries(param) {
|
|
|
|
|
|
const { columns, data } = param;
|
|
|
|
|
|
const sums = [];
|
|
|
|
|
|
columns.forEach((column, index) => {
|
|
|
|
|
|
if (index === 0) {
|
|
|
|
|
|
sums[index] = "合计工时(天)";
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const values =
|
|
|
|
|
|
column.property === "detailList"
|
|
|
|
|
|
? data.map((item) => Number(item[column.property][index - 2]))
|
|
|
|
|
|
: data.map((item) => Number(item[column.property]));
|
|
|
|
|
|
|
|
|
|
|
|
if (!values.every((value) => isNaN(value))) {
|
|
|
|
|
|
sums[index] = values.reduce((prev, curr) => {
|
|
|
|
|
|
const value = Number(curr);
|
|
|
|
|
|
return !isNaN(value) ? prev + curr : prev;
|
|
|
|
|
|
}, 0);
|
|
|
|
|
|
sums[index] = Number(sums[index].toFixed(2));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
sums[index] = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
return sums;
|
|
|
|
|
|
},
|
|
|
|
|
|
handleUserSelect(users) {
|
|
|
|
|
|
if (users.length > 0) {
|
|
|
|
|
|
this.selectedUser = users[0];
|
|
|
|
|
|
this.selectedUserId = users[0].userId;
|
|
|
|
|
|
this.selectedUserName = users[0].nickName;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.selectedUser = null;
|
|
|
|
|
|
this.selectedUserId = "";
|
|
|
|
|
|
this.selectedUserName = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
this.userSelectDialogVisible = false;
|
|
|
|
|
|
this.getUserProject();
|
|
|
|
|
|
},
|
|
|
|
|
|
goToDetail(row) {
|
|
|
|
|
|
this.$router.push({
|
|
|
|
|
|
path: "/project/detail",
|
|
|
|
|
|
query: {
|
|
|
|
|
|
id: row.projectId,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
handleUserClose() {
|
|
|
|
|
|
this.userSelectDialogVisible = false;
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
dateRange: {
|
|
|
|
|
|
deep: true,
|
|
|
|
|
|
handler(newVal) {
|
|
|
|
|
|
const days = [];
|
|
|
|
|
|
if (newVal && newVal.length === 2) {
|
|
|
|
|
|
const start = new Date(this.dateRange[0]);
|
|
|
|
|
|
const end = new Date(this.dateRange[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()}`;
|
|
|
|
|
|
let index = days.length;
|
|
|
|
|
|
days.push({
|
|
|
|
|
|
prop: "detailList",
|
|
|
|
|
|
label: `${dayOfWeek}\n${dateStr}`,
|
|
|
|
|
|
minWidth: 100,
|
|
|
|
|
|
type: "array",
|
|
|
|
|
|
callback: (data, row) => {
|
|
|
|
|
|
return data[index];
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
this.fixedColumns = [
|
|
|
|
|
|
{
|
|
|
|
|
|
prop: "projectName",
|
|
|
|
|
|
label: "项目",
|
|
|
|
|
|
type: "button",
|
|
|
|
|
|
fixed: "left",
|
|
|
|
|
|
width: 160,
|
|
|
|
|
|
callback: (data, row) => {
|
|
|
|
|
|
return `<span style="color:#1686d8;cursor:pointer">${data}</span>`;
|
|
|
|
|
|
},
|
|
|
|
|
|
Event: (data, row) => {
|
|
|
|
|
|
this.goToDetail(row);
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
prop: "allWorkTime",
|
|
|
|
|
|
label: "统计工时\n(天)",
|
|
|
|
|
|
width: 160,
|
|
|
|
|
|
fixed: "left",
|
|
|
|
|
|
},
|
|
|
|
|
|
...days,
|
|
|
|
|
|
];
|
|
|
|
|
|
this.$nextTick(this.getUserProject());
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
|
|
|
this.getDefaultDateRange();
|
|
|
|
|
|
},
|
|
|
|
|
|
beforeDestroy() {},
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.project-progress-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
height: 88vh;
|
|
|
|
|
|
background-color: white;
|
|
|
|
|
|
padding: 30px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.content {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.placeholder-header {
|
|
|
|
|
|
height: 102px; /* 与左侧表格的标题和日期选择器高度一致 */
|
|
|
|
|
|
}
|
|
|
|
|
|
.date-range-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 500px;
|
|
|
|
|
|
margin-left: 100px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.date-range-label {
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.selectBox {
|
|
|
|
|
|
width: 200px;
|
|
|
|
|
|
margin-left: 35px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.selectBox span {
|
|
|
|
|
|
width: 120px;
|
|
|
|
|
|
}
|
|
|
|
|
|
::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;
|
|
|
|
|
|
}
|
|
|
|
|
|
::v-deep .el-table__body-wrapper ::-webkit-scrollbar {
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 确保两个表格的高度一致 */
|
|
|
|
|
|
.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 td {
|
|
|
|
|
|
background-color: #c0c4cc !important;
|
|
|
|
|
|
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
}
|
|
|
|
|
|
.project-name {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.project-name:hover {
|
|
|
|
|
|
text-decoration: underline;
|
|
|
|
|
|
}
|
|
|
|
|
|
::v-deep thead .el-table-fixed-column--left {
|
|
|
|
|
|
background: #d7d7d7 !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
::v-deep .el-table__fixed {
|
|
|
|
|
|
box-shadow: 5px 20px 20px rgba(7, 7, 7, 0.5) !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
.custom-table {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
::v-deep .el-table__footer-wrapper {
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|