|
@@ -7,60 +7,24 @@
|
|
|
<div class="dashboard-subtitle">项目、部门与加班数据概览</div>
|
|
<div class="dashboard-subtitle">项目、部门与加班数据概览</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="dashboard-filter">
|
|
<div class="dashboard-filter">
|
|
|
- <el-radio-group
|
|
|
|
|
- v-model="filterMode"
|
|
|
|
|
- size="small"
|
|
|
|
|
- @change="onFilterModeChange"
|
|
|
|
|
- >
|
|
|
|
|
- <el-radio-button label="month">按月</el-radio-button>
|
|
|
|
|
- <el-radio-button label="range">按区间</el-radio-button>
|
|
|
|
|
- </el-radio-group>
|
|
|
|
|
- <div
|
|
|
|
|
- class="dashboard-date-picker"
|
|
|
|
|
- :class="filterMode === 'month' ? 'is-month' : 'is-range'"
|
|
|
|
|
- >
|
|
|
|
|
- <div
|
|
|
|
|
- v-show="filterMode === 'month'"
|
|
|
|
|
- class="dashboard-date-picker-slot"
|
|
|
|
|
- >
|
|
|
|
|
- <el-date-picker
|
|
|
|
|
- ref="monthDatePicker"
|
|
|
|
|
- class="dashboard-date-picker-input"
|
|
|
|
|
- v-model="selectedMonth"
|
|
|
|
|
- type="month"
|
|
|
|
|
- placeholder="选择年月"
|
|
|
|
|
- value-format="yyyy-MM"
|
|
|
|
|
- :clearable="false"
|
|
|
|
|
- align="right"
|
|
|
|
|
- :append-to-body="true"
|
|
|
|
|
- popper-class="dashboard-date-picker-popper"
|
|
|
|
|
- @focus="onDatePickerFocus"
|
|
|
|
|
- @change="onMonthChange"
|
|
|
|
|
- size="small"
|
|
|
|
|
- ></el-date-picker>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div
|
|
|
|
|
- v-show="filterMode === 'range'"
|
|
|
|
|
- class="dashboard-date-picker-slot"
|
|
|
|
|
- >
|
|
|
|
|
- <el-date-picker
|
|
|
|
|
- ref="rangeDatePicker"
|
|
|
|
|
- class="dashboard-date-picker-input"
|
|
|
|
|
- v-model="dateRange"
|
|
|
|
|
- type="daterange"
|
|
|
|
|
- align="right"
|
|
|
|
|
- range-separator="至"
|
|
|
|
|
- start-placeholder="开始日期"
|
|
|
|
|
- end-placeholder="结束日期"
|
|
|
|
|
- value-format="yyyy-MM-dd"
|
|
|
|
|
- :clearable="false"
|
|
|
|
|
- :append-to-body="true"
|
|
|
|
|
- popper-class="dashboard-date-picker-popper"
|
|
|
|
|
- @focus="onDatePickerFocus"
|
|
|
|
|
- @change="onDateRangeChange"
|
|
|
|
|
- size="small"
|
|
|
|
|
- ></el-date-picker>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="dashboard-date-picker is-range">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ ref="rangeDatePicker"
|
|
|
|
|
+ class="dashboard-date-picker-input"
|
|
|
|
|
+ v-model="dateRange"
|
|
|
|
|
+ type="monthrange"
|
|
|
|
|
+ align="right"
|
|
|
|
|
+ range-separator="至"
|
|
|
|
|
+ start-placeholder="开始月份"
|
|
|
|
|
+ end-placeholder="结束月份"
|
|
|
|
|
+ value-format="yyyy-MM"
|
|
|
|
|
+ :clearable="false"
|
|
|
|
|
+ :append-to-body="true"
|
|
|
|
|
+ popper-class="dashboard-date-picker-popper"
|
|
|
|
|
+ @focus="onDatePickerFocus"
|
|
|
|
|
+ @change="onDateRangeChange"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ ></el-date-picker>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -428,15 +392,9 @@ export default {
|
|
|
const now = new Date();
|
|
const now = new Date();
|
|
|
const year = now.getFullYear();
|
|
const year = now.getFullYear();
|
|
|
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
|
- const lastDay = new Date(year, now.getMonth() + 1, 0).getDate();
|
|
|
|
|
return {
|
|
return {
|
|
|
user: JSON.parse(sessionStorage.getItem("user")),
|
|
user: JSON.parse(sessionStorage.getItem("user")),
|
|
|
- filterMode: "month",
|
|
|
|
|
- selectedMonth: `${year}-${month}`,
|
|
|
|
|
- dateRange: [
|
|
|
|
|
- `${year}-${month}-01`,
|
|
|
|
|
- `${year}-${month}-${String(lastDay).padStart(2, "0")}`,
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ dateRange: [`${year}-${month}`, `${year}-${month}`],
|
|
|
loading1: false,
|
|
loading1: false,
|
|
|
loading2: false,
|
|
loading2: false,
|
|
|
loading3: false,
|
|
loading3: false,
|
|
@@ -540,7 +498,7 @@ export default {
|
|
|
key: "workedProjectCount",
|
|
key: "workedProjectCount",
|
|
|
label: "有工时投入项目数量",
|
|
label: "有工时投入项目数量",
|
|
|
value: `${data.workedProjectCount || 0} 项`,
|
|
value: `${data.workedProjectCount || 0} 项`,
|
|
|
- remark: "当月存在已审核工时",
|
|
|
|
|
|
|
+ remark: "所选区间存在已审核工时",
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
key: "notWorkedExecutingProjectCount",
|
|
key: "notWorkedExecutingProjectCount",
|
|
@@ -550,15 +508,15 @@ export default {
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
key: "totalWorkingTime",
|
|
key: "totalWorkingTime",
|
|
|
- label: "当月总工时",
|
|
|
|
|
|
|
+ label: "区间总工时",
|
|
|
value: `${data.totalWorkingTime || 0} h`,
|
|
value: `${data.totalWorkingTime || 0} h`,
|
|
|
remark: "点击查看有工时投入项目明细",
|
|
remark: "点击查看有工时投入项目明细",
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
key: "totalOvertimeHours",
|
|
key: "totalOvertimeHours",
|
|
|
- label: "当月加班总工时",
|
|
|
|
|
|
|
+ label: "区间加班总工时",
|
|
|
value: `${data.totalOvertimeHours || 0} h`,
|
|
value: `${data.totalOvertimeHours || 0} h`,
|
|
|
- remark: "当月加班工时合计",
|
|
|
|
|
|
|
+ remark: "所选区间加班工时合计",
|
|
|
},
|
|
},
|
|
|
];
|
|
];
|
|
|
},
|
|
},
|
|
@@ -646,59 +604,44 @@ export default {
|
|
|
methods: {
|
|
methods: {
|
|
|
// ========== 基础工具方法 ==========
|
|
// ========== 基础工具方法 ==========
|
|
|
getQueryParams() {
|
|
getQueryParams() {
|
|
|
- if (this.filterMode === "range") {
|
|
|
|
|
- return {
|
|
|
|
|
- startDate: this.dateRange[0],
|
|
|
|
|
- endDate: this.dateRange[1],
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
- return { ymonth: this.selectedMonth };
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ startDate: this.dateRange[0],
|
|
|
|
|
+ endDate: this.dateRange[1],
|
|
|
|
|
+ };
|
|
|
},
|
|
},
|
|
|
getQueryToken() {
|
|
getQueryToken() {
|
|
|
- if (this.filterMode === "range") {
|
|
|
|
|
- return `range_${this.dateRange[0]}_${this.dateRange[1]}`;
|
|
|
|
|
- }
|
|
|
|
|
- return `month_${this.selectedMonth}`;
|
|
|
|
|
|
|
+ return `range_${this.dateRange[0]}_${this.dateRange[1]}`;
|
|
|
},
|
|
},
|
|
|
validateDateRange() {
|
|
validateDateRange() {
|
|
|
- if (this.filterMode !== "range") return true;
|
|
|
|
|
if (!this.dateRange || this.dateRange.length !== 2) {
|
|
if (!this.dateRange || this.dateRange.length !== 2) {
|
|
|
- this.$message({ message: "请选择开始和结束日期", type: "warning" });
|
|
|
|
|
|
|
+ this.$message({ message: "请选择开始和结束月份", type: "warning" });
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
- const start = new Date(this.dateRange[0]);
|
|
|
|
|
- const end = new Date(this.dateRange[1]);
|
|
|
|
|
- if (end < start) {
|
|
|
|
|
- this.$message({ message: "结束日期不能早于开始日期", type: "warning" });
|
|
|
|
|
|
|
+ const [startMonth, endMonth] = this.dateRange;
|
|
|
|
|
+ if (endMonth < startMonth) {
|
|
|
|
|
+ this.$message({ message: "结束月份不能早于开始月份", type: "warning" });
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
- const days =
|
|
|
|
|
- Math.floor((end.getTime() - start.getTime()) / (24 * 3600 * 1000)) + 1;
|
|
|
|
|
- if (days > 366) {
|
|
|
|
|
|
|
+ const monthCount = this.getMonthRangeCount(startMonth, endMonth);
|
|
|
|
|
+ if (monthCount > 12) {
|
|
|
this.$message({
|
|
this.$message({
|
|
|
- message: "查询时间区间最多不能超过一年",
|
|
|
|
|
|
|
+ message: "查询月份区间最多不能超过12个月",
|
|
|
type: "warning",
|
|
type: "warning",
|
|
|
});
|
|
});
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
return true;
|
|
return true;
|
|
|
},
|
|
},
|
|
|
- onFilterModeChange() {
|
|
|
|
|
- this.closeDashboardDatePickers();
|
|
|
|
|
- this.resetWorkedProjectDialog();
|
|
|
|
|
- if (this.validateDateRange()) {
|
|
|
|
|
- this.loadAllCharts();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ getMonthRangeCount(startMonth, endMonth) {
|
|
|
|
|
+ const [startYear, startMon] = startMonth.split("-").map(Number);
|
|
|
|
|
+ const [endYear, endMon] = endMonth.split("-").map(Number);
|
|
|
|
|
+ return (endYear - startYear) * 12 + (endMon - startMon) + 1;
|
|
|
},
|
|
},
|
|
|
onDateRangeChange() {
|
|
onDateRangeChange() {
|
|
|
if (!this.validateDateRange()) return;
|
|
if (!this.validateDateRange()) return;
|
|
|
this.resetWorkedProjectDialog();
|
|
this.resetWorkedProjectDialog();
|
|
|
this.loadAllCharts();
|
|
this.loadAllCharts();
|
|
|
},
|
|
},
|
|
|
- onMonthChange() {
|
|
|
|
|
- this.resetWorkedProjectDialog();
|
|
|
|
|
- this.loadAllCharts();
|
|
|
|
|
- },
|
|
|
|
|
onDatePickerFocus() {
|
|
onDatePickerFocus() {
|
|
|
[0, 30, 80, 150].forEach((delay) => {
|
|
[0, 30, 80, 150].forEach((delay) => {
|
|
|
setTimeout(() => this.fixDatePickerPopperPosition(), delay);
|
|
setTimeout(() => this.fixDatePickerPopperPosition(), delay);
|
|
@@ -736,8 +679,7 @@ export default {
|
|
|
|
|
|
|
|
const gap = 6;
|
|
const gap = 6;
|
|
|
const margin = 8;
|
|
const margin = 8;
|
|
|
- const popperWidth =
|
|
|
|
|
- popper.offsetWidth || (picker.type === "daterange" ? 646 : 322);
|
|
|
|
|
|
|
+ const popperWidth = popper.offsetWidth || 300;
|
|
|
const popperHeight = popper.offsetHeight || 320;
|
|
const popperHeight = popper.offsetHeight || 320;
|
|
|
|
|
|
|
|
let left = rect.right - popperWidth;
|
|
let left = rect.right - popperWidth;
|
|
@@ -761,24 +703,20 @@ export default {
|
|
|
popper.style.zIndex = "3000";
|
|
popper.style.zIndex = "3000";
|
|
|
},
|
|
},
|
|
|
getActiveDatePickerRef() {
|
|
getActiveDatePickerRef() {
|
|
|
- return this.filterMode === "month"
|
|
|
|
|
- ? this.$refs.monthDatePicker
|
|
|
|
|
- : this.$refs.rangeDatePicker;
|
|
|
|
|
|
|
+ return this.$refs.rangeDatePicker;
|
|
|
},
|
|
},
|
|
|
closeDashboardDatePickers() {
|
|
closeDashboardDatePickers() {
|
|
|
- ["monthDatePicker", "rangeDatePicker"].forEach((refName) => {
|
|
|
|
|
- const picker = this.$refs[refName];
|
|
|
|
|
- if (!picker) return;
|
|
|
|
|
- picker.pickerVisible = false;
|
|
|
|
|
- if (picker.picker) {
|
|
|
|
|
- picker.picker.visible = false;
|
|
|
|
|
- }
|
|
|
|
|
- if (picker.popperJS && picker.popperJS.destroy) {
|
|
|
|
|
- picker.popperJS.destroy();
|
|
|
|
|
- picker.popperJS = null;
|
|
|
|
|
- }
|
|
|
|
|
- picker.referenceElm = null;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const picker = this.$refs.rangeDatePicker;
|
|
|
|
|
+ if (!picker) return;
|
|
|
|
|
+ picker.pickerVisible = false;
|
|
|
|
|
+ if (picker.picker) {
|
|
|
|
|
+ picker.picker.visible = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (picker.popperJS && picker.popperJS.destroy) {
|
|
|
|
|
+ picker.popperJS.destroy();
|
|
|
|
|
+ picker.popperJS = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ picker.referenceElm = null;
|
|
|
},
|
|
},
|
|
|
updateOpenDatePickers() {
|
|
updateOpenDatePickers() {
|
|
|
this.fixDatePickerPopperPosition();
|
|
this.fixDatePickerPopperPosition();
|
|
@@ -2454,18 +2392,10 @@ export default {
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.dashboard-date-picker.is-month {
|
|
|
|
|
- width: 220px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
.dashboard-date-picker.is-range {
|
|
.dashboard-date-picker.is-range {
|
|
|
width: 350px;
|
|
width: 350px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.dashboard-date-picker-slot {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
.dashboard-date-picker ::v-deep .dashboard-date-picker-input.el-date-editor {
|
|
.dashboard-date-picker ::v-deep .dashboard-date-picker-input.el-date-editor {
|
|
|
width: 100% !important;
|
|
width: 100% !important;
|
|
|
max-width: 100%;
|
|
max-width: 100%;
|
|
@@ -2473,11 +2403,6 @@ export default {
|
|
|
vertical-align: middle;
|
|
vertical-align: middle;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.dashboard-date-picker.is-month ::v-deep .el-input__inner {
|
|
|
|
|
- padding-left: 30px;
|
|
|
|
|
- padding-right: 10px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
.dashboard-date-picker.is-range ::v-deep .el-range-editor.el-input__inner {
|
|
.dashboard-date-picker.is-range ::v-deep .el-range-editor.el-input__inner {
|
|
|
padding: 3px 10px;
|
|
padding: 3px 10px;
|
|
|
}
|
|
}
|
|
@@ -2839,7 +2764,6 @@ export default {
|
|
|
flex-wrap: wrap;
|
|
flex-wrap: wrap;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .dashboard-date-picker.is-month,
|
|
|
|
|
.dashboard-date-picker.is-range {
|
|
.dashboard-date-picker.is-range {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
max-width: 350px;
|
|
max-width: 350px;
|