|
@@ -1,45 +1,40 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
+ <div class="topbar-right"><b>月统计</b></div>
|
|
|
<b-navbar type="light" variant="faded" class="my-2">
|
|
|
- <b-nav-form>
|
|
|
-
|
|
|
- <!-- <label for="input-month">月份:</label> -->
|
|
|
- <b-input-group class="">
|
|
|
- <b-input-group-prepend is-text>
|
|
|
- <b-icon icon="calendar3"></b-icon>
|
|
|
- </b-input-group-prepend>
|
|
|
- <b-form-input id="input-month" class="mr-sm-2" placeholder="选择月份" v-model="date" @click="openCalendar"></b-form-input>
|
|
|
- </b-input-group>
|
|
|
-
|
|
|
- <b-popover target="input-month" ref="calendar" placement="bottom">
|
|
|
- <div class="year-select my-1">
|
|
|
- <b-button variant="light" size="sm" class="year-minus" @click="yearDecrease"><b-icon icon="chevron-double-left"></b-icon></b-button>
|
|
|
- <div class="year text-center">{{ year }} 年</div>
|
|
|
- <b-button variant="light" size="sm" class="year-plus" @click="yearIncrease"><b-icon icon="chevron-double-right"></b-icon></b-button>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <table id="months" class="months">
|
|
|
- <tr><td @click="setMonth(1)">一月</td><td @click="setMonth(2)">二月</td><td @click="setMonth(3)">三月</td><td @click="setMonth(4)">四月</td></tr>
|
|
|
- <tr><td @click="setMonth(5)">五月</td><td @click="setMonth(6)">六月</td><td @click="setMonth(7)">七月</td><td @click="setMonth(8)">八月</td></tr>
|
|
|
- <tr><td @click="setMonth(9)">九月</td><td @click="setMonth(10)">十月</td><td @click="setMonth(11)">十一月</td><td @click="setMonth(12)">十二月</td></tr>
|
|
|
- </table>
|
|
|
- </div>
|
|
|
- </b-popover>
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
|
|
|
+ <b-form-datepicker
|
|
|
+ id="start-date"
|
|
|
+ v-model="startTime"
|
|
|
+ v-bind="calendarLabels[locale] || {}"
|
|
|
+ :locale="locale"
|
|
|
+ :start-weekday="weekday"
|
|
|
+ :show-decade-nav="showDecadeNav"
|
|
|
+ :hide-header="hideHeader"
|
|
|
+ class="calendar danger"
|
|
|
+ :state="validStartTime"
|
|
|
+ ></b-form-datepicker>
|
|
|
+
|
|
|
+ <b-form-datepicker
|
|
|
+ id="end-date"
|
|
|
+ v-model="endTime"
|
|
|
+ v-bind="calendarLabels[locale] || {}"
|
|
|
+ :locale="locale"
|
|
|
+ :start-weekday="weekday"
|
|
|
+ :show-decade-nav="showDecadeNav"
|
|
|
+ :hide-header="hideHeader"
|
|
|
+ class="calendar mx-2"
|
|
|
+ :state="validEndTime"
|
|
|
+ ></b-form-datepicker>
|
|
|
|
|
|
|
|
|
- <!-- <label for="input-name">姓名:</label> -->
|
|
|
<b-input-group id="input-name" class="">
|
|
|
<b-input-group-prepend is-text>
|
|
|
<b-icon icon="person-square"></b-icon>
|
|
|
</b-input-group-prepend>
|
|
|
|
|
|
- <b-form-input @input="selectEmployee" list="name" class="mr-sm-2" placeholder="请输入姓名"></b-form-input>
|
|
|
+ <b-form-input :state="validUserAccount" @input="selectEmployee" list="name" class="mr-sm-2" placeholder="请输入姓名"></b-form-input>
|
|
|
|
|
|
<datalist id="name">
|
|
|
<option v-for="employee in employeeList" :key="employee.id" :value="employee.account+' - '+employee.realname"></option>
|
|
@@ -48,12 +43,12 @@
|
|
|
</b-input-group>
|
|
|
|
|
|
<b-button variant="primary" class="mx-1" @click="showData">查询</b-button>
|
|
|
- <b-button variant="primary" class="mx-1">导出</b-button>
|
|
|
- </b-nav-form>
|
|
|
+ <b-button variant="primary" class="mx-1" @click="exportData">导出</b-button>
|
|
|
+
|
|
|
</b-navbar>
|
|
|
<b-card class="content-data mx-3 text-center">
|
|
|
- <span class="no-content" v-if="!dataAvailable">请在上方输入搜索条件查询</span>
|
|
|
- <b-table class="datatable" striped hover :items="dataTable" v-if="dataAvailable"></b-table>
|
|
|
+ <div class="no-content my-4" v-if="!dataAvailable">请在上方输入搜索条件查询</div>
|
|
|
+ <b-table class="datatable" sticky-header="100%" hover small :items="dataTable" v-if="dataAvailable" :tbody-tr-class="tableRowColor"></b-table>
|
|
|
</b-card>
|
|
|
|
|
|
</div>
|
|
@@ -73,21 +68,53 @@ export default {
|
|
|
userAccount:'',
|
|
|
employeeList: [],
|
|
|
dataAvailable: false,
|
|
|
- dataTable: []
|
|
|
+ dataTable: [],
|
|
|
+ startTime: undefined,
|
|
|
+ endTime: undefined,
|
|
|
+ locale: 'zh',
|
|
|
+ weekday: 1,
|
|
|
+ showDecadeNav: false,
|
|
|
+ hideHeader: true,
|
|
|
+ calendarLabels: {
|
|
|
+ zh: {
|
|
|
+ weekdayHeaderFormat: 'narrow',
|
|
|
+ labelPrevDecade: '过去十年',
|
|
|
+ labelPrevYear: '上一年',
|
|
|
+ labelPrevMonth: '上个月',
|
|
|
+ labelCurrentMonth: '当前月份',
|
|
|
+ labelNextMonth: '下个月',
|
|
|
+ labelNextYear: '明年',
|
|
|
+ labelNextDecade: '下一个十年',
|
|
|
+ labelToday: '今天',
|
|
|
+ labelSelected: '选定日期',
|
|
|
+ labelNoDateSelected: '未选择日期',
|
|
|
+ labelCalendar: '日历',
|
|
|
+ labelNav: '日历导航',
|
|
|
+ labelHelp: '使用光标键浏览日期'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ validate: false
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
-
|
|
|
+ validStartTime() {
|
|
|
+ return this.validate ? (this.startTime ? true : false) : null;
|
|
|
+ },
|
|
|
+ validEndTime() {
|
|
|
+ return this.validate ? (this.endTime ? true : false) : null;
|
|
|
+ },
|
|
|
+ validUserAccount() {
|
|
|
+ return this.validate ? (this.userAccount ? true : false) : null;
|
|
|
+ }
|
|
|
},
|
|
|
created() {
|
|
|
this.$http.get('/api/personal/getUserList')
|
|
|
.then((result) => {
|
|
|
this.employeeList = result.data.data;
|
|
|
- console.log(this.employeeList)
|
|
|
});
|
|
|
},
|
|
|
mounted() {
|
|
|
- this.year = new Date().getFullYear();
|
|
|
+
|
|
|
|
|
|
|
|
|
},
|
|
@@ -96,59 +123,92 @@ export default {
|
|
|
this.dataAvailable = false;
|
|
|
this.dataTable = [];
|
|
|
},
|
|
|
- onItemClick(item){
|
|
|
- console.log(item)
|
|
|
- },
|
|
|
- openCalendar() {
|
|
|
- this.$refs.calendar.$emit('open');
|
|
|
- this.reset();
|
|
|
- },
|
|
|
- clamp(value, min, max) {
|
|
|
- if(value < min) { return min; }
|
|
|
- else if(value > max) { return max; }
|
|
|
- else { return value; }
|
|
|
- },
|
|
|
- yearDecrease() {
|
|
|
- this.year = this.clamp(this.year - 1, 2000, 3000);
|
|
|
- },
|
|
|
- yearIncrease() {
|
|
|
- this.year = this.clamp(this.year + 1, 2000, 3000);
|
|
|
- },
|
|
|
- setMonth(m) {
|
|
|
- this.month = m;
|
|
|
- this.date = m + '/' + this.year;
|
|
|
- this.$refs.calendar.$emit('close');
|
|
|
- },
|
|
|
selectEmployee(e) {
|
|
|
this.userAccount = e.split(' - ')[0];
|
|
|
this.reset();
|
|
|
},
|
|
|
showData() {
|
|
|
|
|
|
- this.$http.post('/api/personal/workByMonthDetail', {
|
|
|
- "account": this.userAccount,
|
|
|
- "date": (this.year + '-' + this.month + '-' + '01'),
|
|
|
- "pageNum": 0,
|
|
|
- "pageSize": 500,
|
|
|
- "searchKey": ""
|
|
|
- }).then((result) => {
|
|
|
- console.log(result.data.data.list);
|
|
|
- let data = result.data.data.list;
|
|
|
- data.forEach(entry => {
|
|
|
- this.dataTable.push({
|
|
|
- '日期': entry.date,
|
|
|
- '任务号': entry.task,
|
|
|
- '项目名称': entry.projectName,
|
|
|
- '项目号': entry.code,
|
|
|
- '消耗时间(单位:小时)': entry.consumed,
|
|
|
- '部门名称': entry.deptName,
|
|
|
- '姓名': entry.realname,
|
|
|
- '账号': entry.account
|
|
|
+ if(this.startTime && this.endTime && this.userAccount) {
|
|
|
+ this.dataTable = [];
|
|
|
+ this.$http.post('/api/personal/workByDayDetail', {
|
|
|
+ "account": this.userAccount,
|
|
|
+ "startTime": this.startTime,
|
|
|
+ "endTime": this.endTime,
|
|
|
+ "pageNum": 0,
|
|
|
+ "pageSize": 1000,
|
|
|
+ "searchKey": ""
|
|
|
+ }).then((result) => {
|
|
|
+
|
|
|
+ let data = result.data.data.list;
|
|
|
+
|
|
|
+ let dataSummedUp = [];
|
|
|
+ let days = [];
|
|
|
+
|
|
|
+ data.forEach(entry => {
|
|
|
+ if(days.indexOf(entry.date) === -1) {
|
|
|
+ days.push(entry.date);
|
|
|
+ }
|
|
|
});
|
|
|
+
|
|
|
+ days.forEach(day => {
|
|
|
+ let filtered = data.filter(entry => entry.date === day);
|
|
|
+ let sum = 0;
|
|
|
+ let total;
|
|
|
+
|
|
|
+ filtered.forEach(d => {
|
|
|
+ let number = Number(d.consumed);
|
|
|
+
|
|
|
+ sum += number;
|
|
|
+ total = Number(parseFloat(sum).toPrecision(4));
|
|
|
+ });
|
|
|
+ dataSummedUp.push({
|
|
|
+ date: filtered[0].date,
|
|
|
+ consumed: total,
|
|
|
+ deptName: filtered[0].deptName,
|
|
|
+ realname: filtered[0].realname,
|
|
|
+ account: filtered[0].account
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ dataSummedUp.sort((a, b) => {
|
|
|
+ return new Date(a.date) - new Date(b.date);
|
|
|
+ });
|
|
|
+
|
|
|
+ dataSummedUp.forEach(entry => {
|
|
|
+ this.dataTable.push({
|
|
|
+ '日期': entry.date,
|
|
|
+ '消耗时间(单位:小时)': entry.consumed,
|
|
|
+ '部门名称': entry.deptName,
|
|
|
+ '姓名': entry.realname,
|
|
|
+ '账号': entry.account
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.dataAvailable = true;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.validate = true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ exportData() {
|
|
|
+ if(this.dataAvailable === true && this.dataTable.length > 0) {
|
|
|
+ let csv = Object.keys(this.dataTable[0]).join() + '\n';
|
|
|
+ this.dataTable.forEach(row => {
|
|
|
+ csv += Object.values(row).join() + '\n';
|
|
|
});
|
|
|
- this.dataAvailable = true;
|
|
|
- });
|
|
|
|
|
|
+ let hiddenElement = document.createElement('a');
|
|
|
+ hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
|
|
|
+ hiddenElement.target = '_blank';
|
|
|
+ hiddenElement.download = this.startTime + '_' + this.endTime + '_' + this.userAccount + '.csv';
|
|
|
+ hiddenElement.click();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tableRowColor(item, type) {
|
|
|
+ if (!item || type !== 'row') return
|
|
|
+ if (item['消耗时间(单位:小时)'] > 12) return 'table-danger'
|
|
|
+ if (item['消耗时间(单位:小时)'] < 8) return 'table-danger'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -158,31 +218,26 @@ export default {
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
+ .topbar-right {
|
|
|
+ width: 100%;
|
|
|
+ height: 7vh;
|
|
|
+ font-size: 1.2em;
|
|
|
+ padding: 16px 16px;
|
|
|
+ border-bottom: 2px solid lightgrey;
|
|
|
+ }
|
|
|
.content-data {
|
|
|
position: absolute;
|
|
|
height: 90%;
|
|
|
- width: 98%;
|
|
|
- overflow-y: scroll;
|
|
|
- }
|
|
|
- .year-select {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- }
|
|
|
- .year, .year-minus, .year-plus {
|
|
|
- display: inline-block;
|
|
|
+ width: calc(100% - 30px);
|
|
|
}
|
|
|
- .year {
|
|
|
- font-size: 1.3em;
|
|
|
+ .calendar {
|
|
|
+ width: 25%;
|
|
|
}
|
|
|
- .months > tr > td {
|
|
|
- width: 80px;
|
|
|
- height: 40px;
|
|
|
- text-align: center;
|
|
|
- cursor: pointer;
|
|
|
+ #input-name {
|
|
|
+ width: 25%;
|
|
|
}
|
|
|
- .months > tr > td:focus {
|
|
|
- color: blue;
|
|
|
+ .card-body {
|
|
|
+ padding: 0;
|
|
|
}
|
|
|
.datatable {
|
|
|
overflow-y: scroll;
|