Compare commits
37 Commits
0a1371bb9f
...
6a6c6a60ba
| Author | SHA1 | Date |
|---|---|---|
|
|
6a6c6a60ba | 7 months ago |
|
|
754f777aac | 7 months ago |
|
|
7c9987c711 | 7 months ago |
|
|
d7275fd344 | 7 months ago |
|
|
c245b17a3a | 8 months ago |
|
|
d31129d0be | 8 months ago |
|
|
730d6348f7 | 8 months ago |
|
|
849a8482d2 | 8 months ago |
|
|
139376edcf | 8 months ago |
|
|
d7e697a8d6 | 8 months ago |
|
|
b83f9983ee | 8 months ago |
|
|
0f041816d9 | 8 months ago |
|
|
8a3646527b | 8 months ago |
|
|
31822655f5 | 8 months ago |
|
|
36d990e4f1 | 8 months ago |
|
|
ff367ba0d4 | 8 months ago |
|
|
be0550628f | 8 months ago |
|
|
c9873209ed | 8 months ago |
|
|
1223a4d28f | 8 months ago |
|
|
9e1da1cd49 | 8 months ago |
|
|
4932ad54c4 | 8 months ago |
|
|
b547ac1f06 | 8 months ago |
|
|
21b38ba58d | 8 months ago |
|
|
fbdbaa1def | 8 months ago |
|
|
9d83a42dee | 8 months ago |
|
|
172ef1079d | 8 months ago |
|
|
e01b6c58f9 | 8 months ago |
|
|
037acc1fbc | 8 months ago |
|
|
a2190c4a9c | 8 months ago |
|
|
ffb17034e3 | 8 months ago |
|
|
fd922c0721 | 8 months ago |
|
|
2af617bc67 | 8 months ago |
|
|
c50e8d3fff | 8 months ago |
|
|
ae697f0a18 | 8 months ago |
|
|
a86418f21a | 8 months ago |
|
|
5f3e23397a | 8 months ago |
|
|
2bc8a295b7 | 8 months ago |
@ -0,0 +1,19 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function leaveList(params, isLoading = true) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/oa/chart/leave',
|
||||
params,
|
||||
isLoading
|
||||
})
|
||||
}
|
||||
|
||||
export function overtimeList(params,isLoading = true) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/oa/chart/overtime',
|
||||
params,
|
||||
isLoading
|
||||
})
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div>
|
||||
<card-container>
|
||||
<vxe-grid v-bind="tableData">
|
||||
<template #toolbarButtons>
|
||||
<el-date-picker v-model="select.year" type="year" size="small" value-format="yyyy"></el-date-picker>
|
||||
<el-button icon="el-icon-search" type="primary" plain size="small" style="margin-left: 6px;" @click="getData">搜索</el-button>
|
||||
</template>
|
||||
</vxe-grid>
|
||||
</card-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { leaveByYear } from '@/api/attendance'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
select: {
|
||||
year: new Date().getFullYear().toString()
|
||||
},
|
||||
tableData: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
try {
|
||||
const res = await leaveByYear(this.select)
|
||||
if (res[0].other) {
|
||||
this.tableData = {
|
||||
minHeight: 200,
|
||||
maxHeight: 600,
|
||||
toolbarConfig: {
|
||||
print: true,
|
||||
export: true,
|
||||
custom: true,
|
||||
slots: {
|
||||
buttons: 'toolbarButtons'
|
||||
}
|
||||
},
|
||||
sortConfig: {
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
title: '姓名',
|
||||
field: 'name',
|
||||
width: 120,
|
||||
align: 'center',
|
||||
filters: [{ data: '' }],
|
||||
filterRender: {
|
||||
name: 'input'
|
||||
}
|
||||
},
|
||||
...Object.keys(res[0].other)?.map(key => ({
|
||||
title: key,
|
||||
width: 'auto',
|
||||
field: 'other',
|
||||
align: 'center',
|
||||
formatter: ({ cellValue }) => cellValue[key] ?? 0,
|
||||
}))
|
||||
],
|
||||
data: res
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.getData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div>
|
||||
<card-container>
|
||||
<vxe-toolbar print custom export>
|
||||
<template #buttons>
|
||||
<el-date-picker v-model="select.month"
|
||||
type="month" size="small" value-format="yyyy-MM"
|
||||
placeholder="月份" format="yyyy-MM"/>
|
||||
<el-select style="width:250px;margin-left:6px" size="small" @change="changeDepartment" v-model="select.department_id" placeholder="请选择">
|
||||
<el-option v-for="item in departments" :key="item.id" :label="item.name" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-button icon="el-icon-search" type="primary" plain size="small" style="margin-left: 6px;"
|
||||
@click="getList">搜索</el-button>
|
||||
</template>
|
||||
</vxe-toolbar>
|
||||
<vxe-table ref="table" stripe :border='true' style="margin-top: 10px;" :loading="loading"
|
||||
:max-height="1400" :min-height="400"
|
||||
:export-config="{type: 'xlsx',filename:exportName,sheetName:exportName}"
|
||||
:print-config="{}" :column-config="{ resizable: true }"
|
||||
:expand-config="{
|
||||
visibleMethod: () => false,
|
||||
trigger: 'manual'
|
||||
}" :data="tableData"
|
||||
:merge-cells="mergeCells"
|
||||
>
|
||||
<!-- :span-method="mergeCells" -->
|
||||
<vxe-column width="240" header-align="center" align="center" field="department_name" title="科室"></vxe-column>
|
||||
<vxe-column width="180" header-align="center" align="center" field="user.name" title="姓名"></vxe-column>
|
||||
|
||||
<vxe-column header-align="center" align="center" field="over_off" title="结余调休时间">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
{{row.over_off=='0.00'?'0':row.over_off}}
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column header-align="center" align="center" field="overtime" title="本月加班时间">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
{{row.overtime=='0.00'?'0':row.overtime}}
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column header-align="center" align="center" field="time_off" title="本月调休时间">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
{{row.time_off=='0.00'?'0':row.time_off}}
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column header-align="center" align="center" field="expire" title="过期时间">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
{{row.expire=='0.00'?'0':row.expire}}
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column header-align="center" align="center" field="has_time_off" title="剩余调休时间">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
{{row.has_time_off=='0.00'?'0':row.has_time_off}}
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
|
||||
</vxe-table>
|
||||
</card-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
leaveList
|
||||
} from "@/api/chart"
|
||||
import {
|
||||
departmentListNoAuth
|
||||
} from "@/api/common.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tableData: [],
|
||||
select: {
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
month: this.$moment().format('YYYY-MM'),
|
||||
department_id: ''
|
||||
},
|
||||
departments:[],
|
||||
mergeCells:[],
|
||||
exportName:'调休统计表',
|
||||
dName:'全部科室'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getList() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await leaveList(this.select, false);
|
||||
let _arr = res?.timeOff || []
|
||||
_arr.forEach(item=>{
|
||||
item.department_name = item.user.department.name
|
||||
item.sortnumber = item.user.department.sortnumber
|
||||
})
|
||||
_arr.sort((a,b)=>{
|
||||
return a.sortnumber - b.sortnumber
|
||||
})
|
||||
this.tableData = _arr;
|
||||
this.mergeCells = this.generateMergeCells(this.tableData)
|
||||
let date = this.$moment(this.select.month).format("YYYY年MM月")
|
||||
this.exportName = `${date}${this.dName}调休统计表`
|
||||
this.loading = false;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async getDepartmentList() {
|
||||
try {
|
||||
const res = await departmentListNoAuth();
|
||||
let arr = res
|
||||
this.departments = arr
|
||||
this.departments.unshift({
|
||||
id: '',
|
||||
name: '全部'
|
||||
})
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
},
|
||||
changeDepartment(e){
|
||||
if(e){
|
||||
this.departments.map(item=>{
|
||||
if(item.id==e){
|
||||
this.dName = item.name
|
||||
}
|
||||
})
|
||||
}else{
|
||||
this.dName = '全部科室'
|
||||
}
|
||||
},
|
||||
// 合并单元格
|
||||
generateMergeCells(data) {
|
||||
const columns = this.$refs.table.getColumns()
|
||||
let mergeCells = [];
|
||||
const columnsToMerge = ['department_name'];
|
||||
columnsToMerge.forEach(key => {
|
||||
const col = columns.findIndex(item => item['field'] === key);
|
||||
if (col === -1) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let rowspan = 1;
|
||||
const currentValue = data[i][key];
|
||||
for (let j = i + 1; j < data.length; j++) {
|
||||
if (data[j][key] === currentValue) {
|
||||
rowspan++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rowspan > 1) {
|
||||
mergeCells.push({
|
||||
row: i,
|
||||
col,
|
||||
rowspan,
|
||||
colspan: 1
|
||||
});
|
||||
i += rowspan - 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
return mergeCells;
|
||||
},
|
||||
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.getDepartmentList()
|
||||
this.getList()
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs["table"] && this.$refs["toolbar"]) {
|
||||
this.$refs["table"].connect(this.$refs["toolbar"]);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<div>
|
||||
<card-container>
|
||||
<vxe-toolbar print custom export>
|
||||
<template #buttons>
|
||||
<el-date-picker v-model="select.month" type="month" size="small" value-format="yyyy-MM" placeholder="月份"
|
||||
format="yyyy-MM" />
|
||||
<el-select style="width:250px;margin-left:6px" size="small" @change="changeDepartment"
|
||||
v-model="select.department_id" placeholder="请选择">
|
||||
<el-option v-for="item in departments" :key="item.id" :label="item.name" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-button icon="el-icon-search" type="primary" plain size="small" style="margin-left: 6px;"
|
||||
@click="getList">搜索</el-button>
|
||||
</template>
|
||||
</vxe-toolbar>
|
||||
<vxe-table ref="table" stripe :border='true' style="margin-top: 10px;" :loading="loading" :max-height="1400"
|
||||
:min-height="400" :export-config="{type: 'xlsx',filename:exportName,sheetName:exportName}" :print-config="{}"
|
||||
:column-config="{ resizable: true }" :expand-config="{
|
||||
visibleMethod: () => false,
|
||||
trigger: 'manual'
|
||||
}" :data="tableData" :merge-cells="mergeCells">
|
||||
<!-- :span-method="spanMethods" -->
|
||||
<vxe-column width="180" header-align="center" align="center" field="department_name" title="科室"></vxe-column>
|
||||
<vxe-column width="180" header-align="center" align="center" field="name" title="姓名"></vxe-column>
|
||||
<vxe-column width="180" header-align="center" align="center" field="kaishiriqi" title="日期">
|
||||
<template #default="{ row }">
|
||||
{{row.kaishiriqi?row.kaishiriqi.substring(0,11):''}}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column header-align="center" align="center" field="yuanyinshuoming" title="加班事由"></vxe-column>
|
||||
<vxe-column :export-method="exportjbMethod" header-align="center" align="center" field="jiabanshijian"
|
||||
title="加班时间">
|
||||
<template #default="{ row }">
|
||||
{{row.kaishiriqi?row.kaishiriqi.substring(11,row.kaishiriqi.length):''}}-{{row.kaishiriqi?row.jieshushijian.substring(11,row.jieshushijian.length):''}}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column header-align="center" align="center" field="jiabanshichang" title="加班时长(h)"></vxe-column>
|
||||
<!-- <vxe-column header-align="center" align="center" field="day" title="day"></vxe-column> -->
|
||||
<vxe-column header-align="center" align="center" field="allDay" title="本月累计(d)"></vxe-column>
|
||||
|
||||
|
||||
|
||||
</vxe-table>
|
||||
</card-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
overtimeList
|
||||
} from "@/api/chart"
|
||||
import {
|
||||
departmentListNoAuth
|
||||
} from "@/api/common.js"
|
||||
import * as XLSX from "xlsx";
|
||||
import {
|
||||
saveAs
|
||||
} from "file-saver";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tableData: [],
|
||||
select: {
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
month: this.$moment().format('YYYY-MM'),
|
||||
department_id: ''
|
||||
},
|
||||
departments: [],
|
||||
mergeCells: [],
|
||||
exportName: '加班统计表',
|
||||
dName: '全部科室'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getList() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await overtimeList(this.select, false);
|
||||
console.log(res);
|
||||
let data = res?.users || [];
|
||||
this.tableData = this.overtimeData(data)
|
||||
let date = this.$moment(this.select.month).format("YYYY年MM月")
|
||||
this.exportName = `${date}${this.dName}加班统计表`
|
||||
this.loading = false;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async getDepartmentList() {
|
||||
try {
|
||||
const res = await departmentListNoAuth();
|
||||
console.log(res);
|
||||
let arr = res
|
||||
this.departments = arr
|
||||
this.departments.unshift({
|
||||
id: '',
|
||||
name: '全部'
|
||||
})
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
},
|
||||
overtimeData(arr) {
|
||||
let _arr = []
|
||||
const result = [];
|
||||
_arr = arr.filter(item => item.overtime.length > 0)
|
||||
|
||||
_arr.forEach(item => {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
department,
|
||||
overtime
|
||||
} = item;
|
||||
const allDay = overtime.reduce((sum, overtimeItem) => sum + parseFloat(overtimeItem.day), 0);
|
||||
overtime.forEach(overtimeItem => {
|
||||
overtimeItem.pid = id;
|
||||
overtimeItem.name = name;
|
||||
overtimeItem.department_name = department.name
|
||||
overtimeItem.sortnumber = department.sortnumber
|
||||
overtimeItem.department_id = department.id
|
||||
overtimeItem.allDay = parseFloat(allDay).toFixed(2);
|
||||
result.push(overtimeItem);
|
||||
});
|
||||
result.sort((a, b) => {
|
||||
return a.sortnumber - b.sortnumber
|
||||
})
|
||||
});
|
||||
this.mergeCells = this.generateMergeCells(result)
|
||||
return result;
|
||||
},
|
||||
exportjbMethod({
|
||||
row
|
||||
}) {
|
||||
return `${row.kaishiriqi?row.kaishiriqi.substring(11,row.kaishiriqi.length):''}-${row.kaishiriqi?row.jieshushijian.substring(11,row.jieshushijian.length):''}`
|
||||
},
|
||||
changeDepartment(e) {
|
||||
if (e) {
|
||||
this.departments.map(item => {
|
||||
if (item.id == e) {
|
||||
this.dName = item.name
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.dName = '全部科室'
|
||||
}
|
||||
},
|
||||
// 合并单元格
|
||||
generateMergeCells(data) {
|
||||
const columns = this.$refs.table.getColumns()
|
||||
let mergeCells = [];
|
||||
const columnsToMerge = ['department_name', 'name', 'allDay'];
|
||||
columnsToMerge.forEach(key => {
|
||||
const col = columns.findIndex(item => item['field'] === key);
|
||||
if (col === -1) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let rowspan = 1;
|
||||
const currentValue = data[i][key];
|
||||
for (let j = i + 1; j < data.length; j++) {
|
||||
if (data[j][key] === currentValue) {
|
||||
rowspan++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rowspan > 1) {
|
||||
mergeCells.push({
|
||||
row: i,
|
||||
col,
|
||||
rowspan,
|
||||
colspan: 1
|
||||
});
|
||||
i += rowspan - 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
return mergeCells;
|
||||
},
|
||||
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.getDepartmentList()
|
||||
this.getList()
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs["table"] && this.$refs["toolbar"]) {
|
||||
this.$refs["table"].connect(this.$refs["toolbar"]);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
Loading…
Reference in new issue