gz-att-web/src/views/report/attReport/index.vue

571 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="姓名" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入姓名"
clearable
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="部门" prop="orgId">
<treeselect v-model="queryParams.orgId" :options="deptOptions" :normalizer="normalizer" placeholder="选择部门" style="width: 240px"/>
</el-form-item>
<el-form-item label="状态" prop="attStatus">
<el-select
v-model="queryParams.attStatus"
placeholder="状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in dict.type.att_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="日期">
<el-date-picker
v-model="dateRange"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
<el-button type="primary" size="mini" @click="openDialog">批量修改</el-button>
<el-button type="primary" size="mini" @click="openData">数据同步</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col> -->
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" width="80" type="index">
<template slot-scope="scope">
<span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="姓名" align="center" prop="userName" />
<el-table-column label="所属部门" align="center" prop="orgName" :show-overflow-tooltip="true" />
<el-table-column label="考勤日期" align="center" prop="attCurrentDay" width="180" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ formatDate(scope.row.attCurrentDay) }}</span>
</template>
</el-table-column>
<el-table-column label="工作时间外出次数" align="center" prop="normalNum" width="180">
<template slot-scope="scope">
<div
@click="openOutCountList(scope.row)" style="color: #02a7f0; cursor: pointer">
{{ scope.row.outCount}}
</div>
</template>
</el-table-column>
<el-table-column label="打卡记录" align="center" prop="normalNum" >
<template slot-scope="scope">
<div
@click="openAttCountList(scope.row)" style="color: #02a7f0; cursor: pointer">
{{ scope.row.attCount}}
</div>
</template>
</el-table-column>
<el-table-column label="上班打卡时间" align="center" prop="toWorkAttCurrentTime" width="180"></el-table-column>
<el-table-column label="上班状态" align="center" prop="toWorkAttStatus">
<template slot-scope="scope">
<dict-tag :options="dict.type.att_status" :value="scope.row.toWorkAttStatus"/>
</template>
</el-table-column>
<el-table-column label="打卡地址" align="center" prop="toWorkAttAddress" :show-overflow-tooltip="true" />
<el-table-column label="异常备注" align="center" prop="toWorkErrorRemake" :show-overflow-tooltip="true" />
<el-table-column label="下班打卡时间" align="center" prop="offWorkAttCurrentTime" width="180"></el-table-column>
<el-table-column label="下班状态" align="center" prop="offWorkAttStatus">
<template slot-scope="scope">
<dict-tag :options="dict.type.att_status" :value="scope.row.offWorkAttStatus"/>
</template>
</el-table-column>
<el-table-column label="打卡地址" align="center" prop="offWorkAttAddress" :show-overflow-tooltip="true" />
<el-table-column label="异常备注" align="center" prop="offWorkErrorRemake" :show-overflow-tooltip="true" />
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<el-dialog title="批量修改" :visible.sync="open" width="1200px" append-to-body @close="cancel">
<el-table v-loading="loading" :data="dialogList" width="100%" height="500px">
<el-table-column label="序号" type="index" width="55" align="center" fixed/>
<el-table-column label="姓名" align="center" prop="userName" fixed/>
<el-table-column label="所属部门" align="center" prop="orgName" :show-overflow-tooltip="true" width="150" fixed/>
<el-table-column label="考勤日期" align="center" prop="attCurrentDay" :show-overflow-tooltip="true" width="180" fixed>
<template slot-scope="scope">
<span>{{ formatDate(scope.row.attCurrentDay) }}</span>
</template>
</el-table-column>
<el-table-column label="修改上班时间" align="center" prop="toWorkAttCurrentTime" width="240">
<template slot-scope="scope">
<el-date-picker
v-model="scope.row.toWorkAttCurrentTime" :clearable="false"
type="datetime" value-format="yyyy-MM-dd HH:mm:ss" style="width: 95%"
placeholder="选择上班时间">
</el-date-picker>
</template>
</el-table-column>
<el-table-column label="修改上班状态" align="center" prop="toWorkAttStatus" width="180">
<template slot-scope="scope">
<el-select
v-model="scope.row.toWorkAttStatus" @change="changeToWorkAttStatus"
placeholder="修改后上班状态" style="width: 95%">
<el-option
v-for="dict in dict.type.att_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column label="打卡地址" align="center" prop="toWorkAttAddress" :show-overflow-tooltip="true" width="180"/>
<el-table-column label="原因说明" align="center" prop="toErrorRemake" width="200">
<template slot-scope="scope">
<el-input type="textarea" v-model="scope.row.toErrorRemake" maxlength="100"></el-input>
</template>
</el-table-column>
<el-table-column label="修改下班时间" align="center" prop="offWorkAttCurrentTime" width="240">
<template slot-scope="scope">
<el-date-picker
v-model="scope.row.offWorkAttCurrentTime" :clearable="false"
type="datetime" value-format="yyyy-MM-dd HH:mm:ss" style="width: 95%"
placeholder="选择下班时间">
</el-date-picker>
</template>
</el-table-column>
<el-table-column label="修改下班状态" align="center" prop="offWorkAttStatus" width="180">
<template slot-scope="scope">
<el-select
v-model="scope.row.offWorkAttStatus"
placeholder="修改后下班状态" style="width: 95%">
<el-option
v-for="dict in dict.type.att_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column label="打卡地址" align="center" prop="offWorkAttAddress" :show-overflow-tooltip="true" width="180"></el-table-column>
<el-table-column label="原因说明" align="center" prop="offErrorRemake" width="200">
<template slot-scope="scope">
<el-input type="textarea" v-model="scope.row.offErrorRemake" maxlength="100"></el-input>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitEdit">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<!-- 外出次数查询 -->
<el-dialog :title="title" :visible.sync="showOutCount" width="1200px" height="1000px" append-to-body >
<el-form :model="queryRecord" ref="queryFormRecord" size="small" :inline="true" v-show="showSearch" label-width="110px">
<el-form-item>
<!-- <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>-->
</el-form-item>
</el-form>
<el-table v-loading="loadingTwo" :data="tableDataOutCount" width="900px" height = "600px" row-key="id">
<el-table-column label="序号" align="center" width="80" type="index">
<template slot-scope="scope">
<span>{{ (queryRecord.pageNum - 1) * queryRecord.pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="考勤日期" align="center" prop="attCurrentDay" width="180" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ formatDate(scope.row.attCurrentDay) }}</span>
</template>
</el-table-column>
<el-table-column label="打卡时间" align="center" prop="attCurrentTime" width="140" sortable/>
<el-table-column label="打卡地址" align="center" prop="attAddress" sortable/>
</el-table>
<pagination
v-show="totalTwo>0"
:total="totalTwo"
:page.sync="queryRecord.pageNum"
:limit.sync="queryRecord.pageSize"
@pagination="getOutCountList"
/>
</el-dialog>
<!-- 打卡次数记录 -->
<el-dialog :title="title" :visible.sync="showAttCount" width="1200px" height="1000px" append-to-body >
<el-form :model="queryRecord" ref="queryFormRecord" size="small" :inline="true" v-show="showSearch" label-width="110px">
<el-form-item>
<!-- <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>-->
</el-form-item>
</el-form>
<el-table v-loading="loadingAttCount" :data="tableDataAttCount" width="900px" height = "600px" row-key="id">
<el-table-column label="序号" align="center" width="80" type="index">
<template slot-scope="scope">
<span>{{ (queryRecord.pageNum - 1) * queryRecord.pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="考勤日期" align="center" prop="attCurrentDay" width="180" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ formatDate(scope.row.attCurrentDay) }}</span>
</template>
</el-table-column>
<el-table-column label="打卡时间" align="center" prop="attCurrentTime" width="140" sortable/>
<el-table-column label="打卡地址" align="center" prop="attAddress" sortable/>
</el-table>
<pagination
v-show="totalAttCount>0"
:total="totalAttCount"
:page.sync="queryAttCount.pageNum"
:limit.sync="queryAttCount.pageSize"
@pagination="getAttCountList"
/>
</el-dialog>
</div>
</template>
<script>
import { getDetailsList,updateAttDetails,exportAttRecord,synchronous,listDept,getOutCountList,getAttCountList } from "@/api/report/attReport";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import {checkPersonAssignment} from "@/api/system/userInfo";
import {getDetail} from "@/api/report/monthlyError";
export default {
name: "Dict",
dicts: ['att_status'],
components: { Treeselect },
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 字典表格数据
typeList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
dialogList:[],
dialogListOld:[],
// 日期范围
dateRange: [],
deptOptions: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
orgId: undefined,
attStatus: undefined
},
queryRecord: {
pageNum: 1,
pageSize: 10,
userId: undefined,
attCurrentDay: undefined,
userName: undefined,
},
showOutCount:false,
totalTwo: 0,
// 遮罩层
loadingTwo: false,
tableDataOutCount: [],
queryAttCount: {
pageNum: 1,
pageSize: 10,
userId: undefined,
attCurrentDay: undefined,
userName: undefined,
},
showAttCount:false,
totalAttCount: 0,
// 遮罩层
loadingAttCount: false,
tableDataAttCount: [],
};
},
created() {
this.getWeekDates();
this.getDeptList();
this.getList();
},
methods: {
getWeekDates() {
const now = new Date();
const dayOfWeek = now.getDay();
const dayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
const monday = new Date(now);
monday.setDate(monday.getDate() + dayOffset);
const sunday = new Date(monday);
sunday.setDate(sunday.getDate() + 6);
this.dateRange[0]=monday.toISOString().split('T')[0];
this.dateRange[1]=sunday.toISOString().split('T')[0];
},
formatDate(dateString){
const date = new Date(dateString); // 创建日期对象
const year = date.getFullYear(); // 获取年份
const month = String(date.getMonth() + 1).padStart(2, '0'); // 获取月份注意月份从0开始
const day = String(date.getDate()).padStart(2, '0'); // 获取日期
const weekdays = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; // 星期几数组
const weekday = weekdays[date.getDay()]; // 获取星期几
return `${year}-${month}-${day} ${weekday}`; // 组合成所需格式
},
getDeptList(){
listDept().then(response => {
this.deptOptions = this.handleTree(response.data, "id");
});
},
/** 转换部门数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.id,
label: node.orgName,
children: node.children
};
},
/** 查询字典类型列表 */
getList() {
this.loading = true;
console.log(this.dateRange)
if(this.dateRange&&this.dateRange.length>0){
this.queryParams.startDate=this.dateRange[0]
this.queryParams.endDate=this.dateRange[1]
}else{
this.queryParams.startDate=undefined
this.queryParams.endDate=undefined
}
getDetailsList(this.queryParams).then(response => {
this.typeList = response.rows;
this.total = response.total;
this.loading = false;
}
);
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange=[]
this.getWeekDates();
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.dialogList=selection.slice();
},
openDialog(){
console.log(this.dialogList)
if(this.dialogList.length>0){
this.open=true;
this.dialogListOld=JSON.parse(JSON.stringify(this.dialogList));
}else{
this.$message({ message: '请先勾选数据!', type: 'warning' })
}
},
openData(){
if(this.dateRange&&this.dateRange.length>0){
this.queryParams.startDate=this.dateRange[0]
this.queryParams.endDate=this.dateRange[1]
let param={
startDate:this.queryParams.startDate,
endDate : this.queryParams.endDate,
id:'1'
}
console.log(param)
this.$modal.confirm(`是否开始数据同步"${this.queryParams.startDate}~${this.queryParams.endDate}"的数据项?`)
.then(() => {
// 开启加载状态
this.loading = true;
// 执行同步操作
return synchronous(param);
})
.then(response => {
// 同步成功后关闭加载状态并显示成功信息
this.loading = false;
this.$modal.msgSuccess("数据同步成功");
})
.catch(error => {
// 处理任何可能发生的错误,包括确认对话框被取消的情况
this.loading = false; // 确保加载状态关闭
if (error) {
this.$modal.msgError("数据同步失败" + error.message || "未知错误");
}
});
}else{
this.$message({ message: '请先选择日期!', type: 'warning' })
}
},
submitEdit(){
let paramList = []
let hasError = false;
this.dialogList.forEach((newItem, index) => {
const oldItem = this.dialogListOld[index];
// 检查toWorkAttCurrentTime或toWorkAttStatus是否改变
if ((newItem.toWorkAttCurrentTime !== oldItem.toWorkAttCurrentTime || newItem.toWorkAttStatus !== oldItem.toWorkAttStatus) &&
(!newItem.toErrorRemake || newItem.toErrorRemake === "")) {
hasError = true;
this.$message({ message: '上班时间或状态改变时,原因说明不能为空!', type: 'warning' });
}
// 检查offWorkAttCurrentTime或offWorkAttStatus是否改变
if ((newItem.offWorkAttCurrentTime !== oldItem.offWorkAttCurrentTime || newItem.offWorkAttStatus !== oldItem.offWorkAttStatus) &&
(!newItem.offErrorRemake || newItem.offErrorRemake === "")) {
hasError = true;
this.$message({ message: '下班时间或状态改变时,原因说明不能为空!', type: 'warning' });
}
// 如果没有错误,则构建参数对象
if (!hasError) {
let obj = {
userId: newItem.userId,
orgId: newItem.orgId,
attCurrentDay: newItem.attCurrentDay,
toWorkAttCurrentTime: newItem.toWorkAttCurrentTime,
toWorkAttStatus: newItem.toWorkAttStatus,
toErrorRemake: newItem.toErrorRemake,
offWorkAttCurrentTime: newItem.offWorkAttCurrentTime,
offWorkAttStatus: newItem.offWorkAttStatus,
offErrorRemake: newItem.offErrorRemake,
};
paramList.push(obj);
}
});
if (!hasError) {
updateAttDetails(paramList).then(response => {
if (response.code === 200) {
this.$modal.msgSuccess("修改申请提交成功,耐心等待审批请勿重复提交");
this.dialogList = [];
this.open = false;
this.getList();
} else {
this.$message({ message: '修改申请提交失败!', type: 'warning' });
}
});
} else {
// 如果存在错误,则不清空或提交数据
console.log("存在错误未提交数据");
}
},
cancel(){
this.getList();
this.open=false;
},
/** 导出按钮操作 */
handleExport() {
this.queryParams.exportType="考勤明细"
exportAttRecord(this.queryParams).then(res => {
this.downloadFile({ fileName: `考勤记录_${new Date().getTime()}.xlsx`, fileData: res, fileType: 'application/vnd.ms-excel;charset=utf-8' })
})
},
//打开工作时间外出次数
openOutCountList(row){
this.title = "工作时间外出次数";
this.queryRecord.userId = row.userId;
this.queryRecord.attCurrentDay = row.attCurrentDay;
this.showOutCount = true;
this.getOutCountList();
},
/** 查询工作时间外出次数列表 */
getOutCountList() {
this.loadingTwo = true;
getOutCountList(this.queryRecord).then(response => {
this.tableDataOutCount = response.rows;
this.totalTwo = response.total;
this.loadingTwo = false;
});
},
//打开打卡次数记录
openAttCountList(row){
this.title = "打卡记录当天1200至第二天凌晨0500";
this.queryAttCount.userId = row.userId;
this.queryAttCount.attCurrentDay = row.attCurrentDay;
this.showAttCount = true;
this.getAttCountList();
},
/** 查询打卡次数记录列表 */
getAttCountList() {
this.loadingAttCount = true;
getAttCountList(this.queryAttCount).then(response => {
this.tableDataAttCount = response.rows;
this.totalAttCount = response.total;
this.loadingAttCount = false;
});
},
}
};
</script>