316 lines
7.9 KiB
Vue
316 lines
7.9 KiB
Vue
<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"
|
||
:tableHeight="600"
|
||
></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>
|