新增操作记录功能
This commit is contained in:
parent
4a09fa18e4
commit
8aed1536bd
@ -35,3 +35,11 @@ export function updateStatistical(data) {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function getAttendanceOper(id){
|
||||
return request({
|
||||
url: '/attendance/statistical/oper/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@ -11,5 +11,47 @@ export default{
|
||||
lastDay.setMonth(lastDay.getMonth() + 1, 0); // 设置日期为下个月的第一天的前一天,即当前月的最后一天
|
||||
// 格式化日期为YYYY-MM-DD格式
|
||||
return lastDay.toISOString().slice(0, 10);
|
||||
}
|
||||
},
|
||||
|
||||
formatDate(date, pattern){
|
||||
// 如果是时间戳,先转换为 Date 对象
|
||||
if (typeof date === 'number') {
|
||||
date = new Date(date);
|
||||
}
|
||||
// 如果是字符串,尝试转换为 Date 对象
|
||||
if (typeof date === 'string') {
|
||||
date = new Date(date.replace(/-/g, '/')); // 处理 Safari 兼容性
|
||||
}
|
||||
|
||||
const options = {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false // 24小时制
|
||||
};
|
||||
|
||||
// 简单格式直接返回
|
||||
if (pattern === 'yyyy-MM-dd HH:mm:ss') {
|
||||
return date.toLocaleString('zh-CN', options).replace(/\//g, '-');
|
||||
}
|
||||
|
||||
// 自定义格式解析(示例支持 yyyy、MM、dd、HH、mm、ss)
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hour = String(date.getHours()).padStart(2, '0');
|
||||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||||
const second = String(date.getSeconds()).padStart(2, '0');
|
||||
|
||||
return pattern.replace('yyyy', year)
|
||||
.replace('MM', month)
|
||||
.replace('dd', day)
|
||||
.replace('HH', hour)
|
||||
.replace('mm', minute)
|
||||
.replace('ss', second);
|
||||
|
||||
}
|
||||
}
|
||||
69
src/views/attendance/statistical/DataComparison/index.vue
Normal file
69
src/views/attendance/statistical/DataComparison/index.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>原数据</span>
|
||||
</div>
|
||||
<div class="text item">
|
||||
<el-descriptions class="margin-top" :column="3" size="medium" border>
|
||||
<el-descriptions-item label="应出勤"><el-tag v-if="oldInfo.shouldAttendance != newInfo.shouldAttendance" type="danger">{{oldInfo.shouldAttendance}}</el-tag><span v-else>{{oldInfo.shouldAttendance}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="实出勤"><el-tag v-if="oldInfo.realAttendance != newInfo.realAttendance" type="danger">{{oldInfo.realAttendance}}</el-tag><span v-else>{{oldInfo.realAttendance}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="打卡时长"><el-tag v-if="oldInfo.essentialAttendance != newInfo.essentialAttendance" type="danger">{{oldInfo.essentialAttendance}}</el-tag><span v-else>{{oldInfo.essentialAttendance}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="加班时长"><el-tag v-if="oldInfo.workOvertimeNumber != newInfo.workOvertimeNumber" type="danger">{{oldInfo.workOvertimeNumber}}</el-tag><span v-else>{{oldInfo.workOvertimeNumber}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="特殊加班"><el-tag v-if="oldInfo.overTimeHours != newInfo.overTimeHours" type="danger">{{oldInfo.overTimeHours}}</el-tag><span v-else>{{oldInfo.overTimeHours}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="请假时长"><el-tag v-if="oldInfo.absenteeism != newInfo.absenteeism" type="danger">{{oldInfo.absenteeism}}</el-tag><span v-else>{{oldInfo.absenteeism}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="异常次数"><el-tag v-if="oldInfo.lateNumber != newInfo.lateNumber" type="danger">{{oldInfo.lateNumber}}</el-tag><span v-else>{{oldInfo.lateNumber}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="中班次数"><el-tag v-if="oldInfo.middleShiftNumber != newInfo.middleShiftNumber" type="danger">{{oldInfo.middleShiftNumber}}</el-tag><span v-else>{{oldInfo.middleShiftNumber}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="夜班次数"><el-tag v-if="oldInfo.nightNumber != newInfo.nightNumber" type="danger">{{oldInfo.nightNumber}}</el-tag><span v-else>{{oldInfo.nightNumber}}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>新数据</span>
|
||||
</div>
|
||||
<div class="text item">
|
||||
<el-descriptions class="margin-top" :column="3" size="medium" border>
|
||||
<el-descriptions-item label="应出勤"><el-tag v-if="oldInfo.shouldAttendance != newInfo.shouldAttendance" type="danger">{{newInfo.shouldAttendance}}</el-tag><span v-else>{{newInfo.shouldAttendance}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="实出勤"><el-tag v-if="oldInfo.realAttendance != newInfo.realAttendance" type="danger">{{newInfo.realAttendance}}</el-tag><span v-else>{{newInfo.realAttendance}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="打卡时长"><el-tag v-if="oldInfo.essentialAttendance != newInfo.essentialAttendance" type="danger">{{newInfo.essentialAttendance}}</el-tag><span v-else>{{newInfo.essentialAttendance}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="加班时长"><el-tag v-if="oldInfo.workOvertimeNumber != newInfo.workOvertimeNumber" type="danger">{{newInfo.workOvertimeNumber}}</el-tag><span v-else>{{newInfo.workOvertimeNumber}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="特殊加班"><el-tag v-if="oldInfo.overTimeHours != newInfo.overTimeHours" type="danger">{{newInfo.overTimeHours}}</el-tag><span v-else>{{newInfo.overTimeHours}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="请假时长"><el-tag v-if="oldInfo.absenteeism != newInfo.absenteeism" type="danger">{{newInfo.absenteeism}}</el-tag><span v-else>{{newInfo.absenteeism}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="异常次数"><el-tag v-if="oldInfo.lateNumber != newInfo.lateNumber" type="danger">{{newInfo.lateNumber}}</el-tag><span v-else>{{newInfo.lateNumber}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="中班次数"><el-tag v-if="oldInfo.middleShiftNumber != newInfo.middleShiftNumber" type="danger">{{newInfo.middleShiftNumber}}</el-tag><span v-else>{{newInfo.middleShiftNumber}}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="夜班次数"><el-tag v-if="oldInfo.nightNumber != newInfo.nightNumber" type="danger">{{newInfo.nightNumber}}</el-tag><span v-else>{{newInfo.nightNumber}}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "DataComparison",
|
||||
props: {
|
||||
oldInfo: {
|
||||
|
||||
},
|
||||
newInfo: {
|
||||
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="员工姓名" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入员工姓名" @keyup.enter.native="handleQuery"/>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item label="所属月份" prop="month">
|
||||
<el-date-picker clearable
|
||||
@ -132,6 +133,13 @@
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['attendance:statistical:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
v-hasPermi="['attendance:statistical:oper']"
|
||||
@click="viewInfo(scope.row)"
|
||||
>操作记录</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -362,11 +370,30 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-drawer
|
||||
:title="info.title"
|
||||
:visible.sync="info.infoOpen"
|
||||
:size="'60%'"
|
||||
direction="rtl">
|
||||
<div class="block">
|
||||
<el-timeline >
|
||||
<el-timeline-item v-for="(activity, index) in info.activities" :key="index" placement="top" :timestamp="activity.operationTime">
|
||||
<el-card>
|
||||
<div slot="header" class="clearfix">
|
||||
<span>数据修改人: {{activity.operationAccount}}</span>
|
||||
</div>
|
||||
<data-comparison :oldInfo="activity.oldInfo" :newInfo="activity.newInfo"/>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listStatistical,correctStatistics,updateStatistical,getStatistical} from "@/api/attendance/statistical";
|
||||
import { listStatistical,correctStatistics,updateStatistical,getStatistical, getAttendanceOper} from "@/api/attendance/statistical";
|
||||
import { listAllDepts } from '@/api/system/dept';
|
||||
import {listAttendanceByParams} from "@/api/attendance/attendance";
|
||||
import {listDetailByStaffIdAndMonth} from "@/api/personnelMatters/overTime";
|
||||
@ -375,10 +402,13 @@ import { listAbnormalDetails } from '@/api/attendance/abnormal'
|
||||
import { getToken } from "@/utils/auth";
|
||||
import Treeselect from '@riophae/vue-treeselect'
|
||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||
import DateUtils from "../../../plugins/DateUtils";
|
||||
|
||||
import DataComparison from '@/views/attendance/statistical/DataComparison/index.vue';
|
||||
|
||||
export default {
|
||||
name: "Statistical",
|
||||
components: { Treeselect },
|
||||
components: { Treeselect,DataComparison },
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
@ -454,6 +484,12 @@ export default {
|
||||
//导出详情
|
||||
openDetail: false,
|
||||
form:{},
|
||||
info:{
|
||||
infoOpen: false,
|
||||
title: "",
|
||||
activities: [
|
||||
]
|
||||
},
|
||||
// 表单校验
|
||||
rules: {
|
||||
handleDate: [
|
||||
@ -468,6 +504,17 @@ export default {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
|
||||
viewInfo(row){
|
||||
this.info.title=row.name+" ["+DateUtils.formatDate(row.month, 'yyyy-MM') +"] 操作记录";
|
||||
getAttendanceOper(row.id).then(response => {
|
||||
this.info.activities = response.data;
|
||||
this.info.infoOpen=true;
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
/** 获取部门 */
|
||||
getDeptList(){
|
||||
listAllDepts().then(response => {
|
||||
@ -639,6 +686,7 @@ export default {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
console.log(this.form)
|
||||
updateStatistical(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.openStatic = false;
|
||||
|
||||
@ -153,6 +153,13 @@
|
||||
@click="handleUpdateDetail(scope.row)"
|
||||
v-hasPermi="['personnelMatters:leaveDetail:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDeleteDetail(scope.row)"
|
||||
v-hasPermi="['personnelMatters:leaveDetail:remove']"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -197,7 +204,7 @@
|
||||
|
||||
<script>
|
||||
import { listLeave, getLeave, delLeave, addLeave, updateLeave,autoTypeList,getNewDicts } from "@/api/personnelMatters/leave";
|
||||
import { listDetail, getDetail, addDetail, updateDetail, calculationLeaveHour } from "@/api/personnelMatters/leaveDetail";
|
||||
import { listDetail, getDetail, addDetail, updateDetail, calculationLeaveHour,delDetail } from "@/api/personnelMatters/leaveDetail";
|
||||
import { listAllDepts } from '@/api/system/dept';
|
||||
import {listStaffAll, listStaffByDept} from '@/api/system/staff';
|
||||
import Treeselect from "@riophae/vue-treeselect";
|
||||
@ -316,6 +323,15 @@ export default {
|
||||
this.title = "修改请假详情";
|
||||
});
|
||||
},
|
||||
handleDeleteDetail(row){
|
||||
delDetail(row.id).then(response => {
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
this.detail.detailOpen = false;
|
||||
this.detailOpen(this.detail.row);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
cancelDetail() {
|
||||
this.detail.detailOpen = false;
|
||||
},
|
||||
|
||||
@ -341,8 +341,8 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="打卡位置:" prop="timeClock">
|
||||
<el-select v-model="form.timeClock" placeholder="选择打卡机" clearable >
|
||||
<el-form-item label="打卡位置:" prop="timeClockList">
|
||||
<el-select v-model="form.timeClockList" multiple placeholder="选择打卡机" style="width: 100%;">
|
||||
<el-option
|
||||
v-for="dict in dict.type.time_clock"
|
||||
:key="dict.value"
|
||||
@ -350,6 +350,15 @@
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<!-- <el-select v-model="form.timeClock" placeholder="选择打卡机" clearable >
|
||||
<el-option
|
||||
v-for="dict in dict.type.time_clock"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select> -->
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -1051,7 +1060,7 @@ export default {
|
||||
imageUrl:[
|
||||
{ required: true, message: "请上传员工头像", trigger: "blur" },
|
||||
],
|
||||
timeClock: [
|
||||
timeClockList: [
|
||||
{ required: true, message: "打卡机不能为空", trigger: "blur" }
|
||||
],
|
||||
jobCode: [
|
||||
@ -1159,6 +1168,7 @@ export default {
|
||||
imageUrl:null,
|
||||
fileId:null,
|
||||
timeClock:null,
|
||||
timeClockList:null,
|
||||
subsidyList:null
|
||||
};
|
||||
this.resetForm("form");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user