Browse Source

1.考勤添加午休设置

master
wangqiang 2 days ago
parent
commit
1911110ee2
1 changed files with 200 additions and 90 deletions
  1. 200
    90
      src/views/oa/attendance/groups/index.vue

+ 200
- 90
src/views/oa/attendance/groups/index.vue View File

@click="handleAdd" @click="handleAdd"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<!-- <el-col :span="1.5">
<el-button
v-hasPermi="['demo:leave:edit']"
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['demo:leave:remove']"
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['demo:leave:export']"
type="warning"
plain
icon="el-icon-download"
size="mini"
:loading="exportLoading"
@click="handleExport"
>导出</el-button>
</el-col> -->

<right-toolbar :show-search.sync="showSearch" @queryTable="getList" /> <right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
</el-row> </el-row>


<el-form-item label="考勤组名称" prop="name"> <el-form-item label="考勤组名称" prop="name">
<el-input v-model="attendanceGroup.name" placeholder="请输入考勤组名称"></el-input> <el-input v-model="attendanceGroup.name" placeholder="请输入考勤组名称"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="attendanceGroup.description" placeholder="请输入描述信息"></el-input> <el-input v-model="attendanceGroup.description" placeholder="请输入描述信息"></el-input>
</el-form-item> </el-form-item>
<!-- 考勤时间设置 --> <!-- 考勤时间设置 -->
<el-form-item label="工作日设置"> <el-form-item label="工作日设置">
<el-checkbox-group v-model="attendanceGroup.workDays"> <el-checkbox-group v-model="attendanceGroup.workDays">
<el-checkbox v-for="day in workDays" :key="day.value" :label="day.value">{{ day.label }}</el-checkbox> <el-checkbox v-for="day in workDays" :key="day.value" :label="day.value">{{ day.label }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<el-form-item label="上班时间" prop="workStartTime"> <el-form-item label="上班时间" prop="workStartTime">
<el-time-picker <el-time-picker
v-model="attendanceGroup.workStartTime" v-model="attendanceGroup.workStartTime"
placeholder="选择上班时间" placeholder="选择上班时间"
></el-time-picker> ></el-time-picker>
</el-form-item> </el-form-item>
<el-form-item label="迟到浮动" prop="lateRange"> <el-form-item label="迟到浮动" prop="lateRange">
<el-col :span="12"> <el-col :span="12">
<el-switch <el-switch
<div class="slider-value">{{ attendanceGroup.lateRange }}分钟</div> <div class="slider-value">{{ attendanceGroup.lateRange }}分钟</div>
</el-col> </el-col>
</el-form-item> </el-form-item>
<el-form-item label="下班时间" prop="workEndTime"> <el-form-item label="下班时间" prop="workEndTime">
<el-time-picker <el-time-picker
v-model="attendanceGroup.workEndTime" v-model="attendanceGroup.workEndTime"
placeholder="选择下班时间" placeholder="选择下班时间"
></el-time-picker> ></el-time-picker>
</el-form-item> </el-form-item>

<!-- 午休时间设置 -->
<el-form-item label="午休开始时间" prop="lunchStartTime">
<el-time-picker
v-model="attendanceGroup.lunchStartTime"
format="HH:mm"
value-format="HH:mm"
placeholder="选择午休开始时间"
@change="calculateLunchHours"
></el-time-picker>
</el-form-item>

<el-form-item label="午休结束时间" prop="lunchEndTime">
<el-time-picker
v-model="attendanceGroup.lunchEndTime"
format="HH:mm"
value-format="HH:mm"
placeholder="选择午休结束时间"
@change="calculateLunchHours"
></el-time-picker>
</el-form-item>

<el-form-item label="午休时间" prop="lunchHours">
<el-input
v-model="lunchHoursDisplay"
placeholder="午休时间(小时)"
readonly
style="width: 200px"
>
<template slot="append">小时</template>
</el-input>
</el-form-item>

<el-form-item label="早退浮动" prop="earlyRange"> <el-form-item label="早退浮动" prop="earlyRange">
<el-col :span="12"> <el-col :span="12">
<el-switch <el-switch
<div class="slider-value">{{ attendanceGroup.earlyRange }}分钟</div> <div class="slider-value">{{ attendanceGroup.earlyRange }}分钟</div>
</el-col> </el-col>
</el-form-item> </el-form-item>
<!-- 打卡配置 --> <!-- 打卡配置 -->
<el-form-item label="打卡区域" prop="areaId"> <el-form-item label="打卡区域" prop="areaId">
<el-select <el-select
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 关联员工 --> <!-- 关联员工 -->
<el-form-item label="关联员工"> <el-form-item label="关联员工">
<el-button <el-button
> >
<i class="el-icon-plus"></i> 选择员工 <i class="el-icon-plus"></i> 选择员工
</el-button> </el-button>
<el-table <el-table
:data="attendanceGroup.members" :data="attendanceGroup.members"
style="width: 100%; margin-top: 20px" style="width: 100%; margin-top: 20px"
form: {}, form: {},
// 结果 // 结果
warnResult: '', warnResult: '',
// 表单校验
rules: {
snapshotUrl: [
{ required: true, message: '图片快照不能为空', trigger: 'blur' }
]
},
daka_check_in_status: [{label: '正常', value: '0'},{label: '迟到', value: '1'},{label: '缺卡', value: '2'}], daka_check_in_status: [{label: '正常', value: '0'},{label: '迟到', value: '1'},{label: '缺卡', value: '2'}],
// 地图相关 // 地图相关
map: null, map: null,
circle: null, circle: null,
mapHeight: '400px', mapHeight: '400px',
baiduMapKey: '你的百度地图API Key', // 替换为你的API Key baiduMapKey: '你的百度地图API Key', // 替换为你的API Key
// 表单数据 // 表单数据
formData: { formData: {
id: null, id: null,
radius: 500, // 默认半径500米 radius: 500, // 默认半径500米
enabled: false enabled: false
}, },
// 区域列表 // 区域列表
areaList: [], areaList: [],
// 模态框状态 // 模态框状态
showDeleteModal: false, showDeleteModal: false,
currentDeletingArea: null, currentDeletingArea: null,
workDays: ['mon', 'tue', 'wed', 'thu', 'fri'], workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
workStartTime: '09:00', workStartTime: '09:00',
workEndTime: '18:00', workEndTime: '18:00',
lunchStartTime: '12:00',
lunchEndTime: '13:00',
lunchHours: 1,
allowLate: false, allowLate: false,
lateRange: 15, lateRange: 15,
allowEarly: false, allowEarly: false,
workDays: ['mon', 'tue', 'wed', 'thu', 'fri'], workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
workStartTime: '09:00', workStartTime: '09:00',
workEndTime: '18:00', workEndTime: '18:00',
lunchStartTime: '12:00',
lunchEndTime: '13:00',
lunchHours: 1,
allowLate: false, allowLate: false,
lateRange: 15, lateRange: 15,
allowEarly: false, allowEarly: false,
workEndTime: [ workEndTime: [
{ required: true, message: '请选择下班时间', trigger: 'change' } { required: true, message: '请选择下班时间', trigger: 'change' }
], ],
lunchStartTime: [
{ required: true, message: '请选择午休开始时间', trigger: 'change' }
],
lunchEndTime: [
{ required: true, message: '请选择午休结束时间', trigger: 'change' }
],
areaId: [ areaId: [
{ required: true, message: '请选择打卡区域', trigger: 'change' } { required: true, message: '请选择打卡区域', trigger: 'change' }
] ]
filteredUsers() { filteredUsers() {
// 获取不在当前考勤组中的用户 // 获取不在当前考勤组中的用户
const groupMemberIds = this.attendanceGroup.members.map(member => member.id); const groupMemberIds = this.attendanceGroup.members.map(member => member.id);
const availableUsers = this.users.filter(user =>
const availableUsers = this.users.filter(user =>
!groupMemberIds.includes(user.id) !groupMemberIds.includes(user.id)
); );
// 应用搜索过滤 // 应用搜索过滤
if (!this.userSearchKeyword) return availableUsers; if (!this.userSearchKeyword) return availableUsers;
const keyword = this.userSearchKeyword.toLowerCase(); const keyword = this.userSearchKeyword.toLowerCase();
return availableUsers.filter(user =>
user.name.toLowerCase().includes(keyword) ||
return availableUsers.filter(user =>
user.name.toLowerCase().includes(keyword) ||
user.employeeId.toLowerCase().includes(keyword) || user.employeeId.toLowerCase().includes(keyword) ||
user.department.toLowerCase().includes(keyword) || user.department.toLowerCase().includes(keyword) ||
user.position.toLowerCase().includes(keyword) user.position.toLowerCase().includes(keyword)
); );
},
// 午休时间显示
lunchHoursDisplay() {
// 实时计算午休时间
if (!this.attendanceGroup.lunchStartTime || !this.attendanceGroup.lunchEndTime) {
return '0';
}

const startTime = this.parseTimeToMinutes(this.attendanceGroup.lunchStartTime);
const endTime = this.parseTimeToMinutes(this.attendanceGroup.lunchEndTime);

if (endTime <= startTime) {
return '0';
}

const diffMinutes = endTime - startTime;
const hours = diffMinutes / 60;

// 以0.5为基准进行向下取整计算
const result = Math.floor(hours * 2) / 2;
return result.toString();
} }
}, },
mounted() { mounted() {
// 加载打卡区域数据(实际项目中从API获取) // 加载打卡区域数据(实际项目中从API获取)
this.loadCheckInAreas(); this.loadCheckInAreas();
}, },
watch: {
// 监听午休时间变化,自动计算午休小时数
'attendanceGroup.lunchStartTime': {
handler: function(newVal, oldVal) {
console.log('午休开始时间变化:', newVal);
if (newVal && this.attendanceGroup.lunchEndTime) {
this.$nextTick(() => {
this.calculateLunchHours();
});
}
},
immediate: true
},
'attendanceGroup.lunchEndTime': {
handler: function(newVal, oldVal) {
console.log('午休结束时间变化:', newVal);
if (newVal && this.attendanceGroup.lunchStartTime) {
this.$nextTick(() => {
this.calculateLunchHours();
});
}
},
immediate: true
}
},
methods: { methods: {
// 解析时间字符串为分钟数
parseTimeToMinutes(timeStr) {
if (!timeStr) return 0;
const [hours, minutes] = timeStr.split(':').map(Number);
return hours * 60 + minutes;
},

// 计算午休时间
calculateLunchHours() {
if (!this.attendanceGroup.lunchStartTime || !this.attendanceGroup.lunchEndTime) {
this.attendanceGroup.lunchHours = 0;
return;
}

const startTime = this.parseTimeToMinutes(this.attendanceGroup.lunchStartTime);
const endTime = this.parseTimeToMinutes(this.attendanceGroup.lunchEndTime);

if (endTime <= startTime) {
this.attendanceGroup.lunchHours = 0;
return;
}

const diffMinutes = endTime - startTime;
const hours = diffMinutes / 60;

// 以0.5为基准进行向下取整计算
// 例如:0.7按0.5算,1.7按1.5算
this.attendanceGroup.lunchHours = Math.floor(hours * 2) / 2;

// 调试输出
console.log(`午休时间计算: ${this.attendanceGroup.lunchStartTime} - ${this.attendanceGroup.lunchEndTime} = ${hours}小时,计算结果: ${this.attendanceGroup.lunchHours}小时`);
},

test(){ test(){
test({userId:1}).then((res) => { test({userId:1}).then((res) => {
console.log(res) console.log(res)
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
// this.reset() // this.reset()
this.attendanceGroup = this.attendanceGroupModel
this.attendanceGroup = { ...this.attendanceGroupModel }
// 确保午休时间正确初始化
this.calculateLunchHours();
this.open = true this.open = true
}, },


this.open = true this.open = true
// 复制对象,避免直接修改原始数据 // 复制对象,避免直接修改原始数据
this.attendanceGroup = { ...area }; this.attendanceGroup = { ...area };

// 确保午休时间字段存在
if (!this.attendanceGroup.lunchStartTime) {
this.attendanceGroup.lunchStartTime = '12:00';
}
if (!this.attendanceGroup.lunchEndTime) {
this.attendanceGroup.lunchEndTime = '13:00';
}
if (this.attendanceGroup.lunchHours === undefined) {
this.attendanceGroup.lunchHours = 1;
}

// 重新计算午休时间
this.calculateLunchHours();

this.selectGroup(area.id) this.selectGroup(area.id)


}, },
console.log(this.attendanceGroup) console.log(this.attendanceGroup)
this.$refs.groupForm.validate(valid => { this.$refs.groupForm.validate(valid => {
if (valid) { if (valid) {
// 计算午休时间
this.calculateLunchHours();

// 实际项目中调用API创建 // 实际项目中调用API创建
const newGroup = { const newGroup = {
id: this.attendanceGroup.id, id: this.attendanceGroup.id,
workDays: this.attendanceGroup.workDays, workDays: this.attendanceGroup.workDays,
workStartTime: this.attendanceGroup.workStartTime, workStartTime: this.attendanceGroup.workStartTime,
workEndTime: this.attendanceGroup.workEndTime, workEndTime: this.attendanceGroup.workEndTime,
lunchStartTime: this.attendanceGroup.lunchStartTime,
lunchEndTime: this.attendanceGroup.lunchEndTime,
lunchHours: this.attendanceGroup.lunchHours,
allowLate: this.attendanceGroup.allowLate, allowLate: this.attendanceGroup.allowLate,
lateRange: this.attendanceGroup.lateRange, lateRange: this.attendanceGroup.lateRange,
allowEarly: this.attendanceGroup.allowEarly, allowEarly: this.attendanceGroup.allowEarly,
this.$message.warning('请选择员工'); this.$message.warning('请选择员工');
return; return;
} }
// 添加选中的员工到考勤组 // 添加选中的员工到考勤组
// const map = new Map(); // const map = new Map();
// [...this.attendanceGroup.members, ...this.selectedUsers].forEach(item => map.set(item.id, item)); // [...this.attendanceGroup.members, ...this.selectedUsers].forEach(item => map.set(item.id, item));
// ] // ]
// } // }
// ]; // ];
// 模拟员工数据 // 模拟员工数据
// this.users = [ // this.users = [
// { id: 1, name: '张三', employeeId: 'EMP001', department: '研发部', position: '高级工程师' }, // { id: 1, name: '张三', employeeId: 'EMP001', department: '研发部', position: '高级工程师' },
// console.log(this.attendanceGroups) // console.log(this.attendanceGroups)
}) })
}, },
// 加载打卡区域数据(实际项目中从API获取) // 加载打卡区域数据(实际项目中从API获取)
loadCheckInAreas() { loadCheckInAreas() {
// this.checkInAreas = [ // this.checkInAreas = [
this.checkInAreas = res this.checkInAreas = res
}) })
}, },
// 重置表单 // 重置表单
resetForm() { resetForm() {
this.attendanceGroup = { this.attendanceGroup = {
workDays: ['mon', 'tue', 'wed', 'thu', 'fri'], workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
workStartTime: '09:00', workStartTime: '09:00',
workEndTime: '18:00', workEndTime: '18:00',
lunchStartTime: '12:00',
lunchEndTime: '13:00',
lunchHours: 1,
allowLate: true, allowLate: true,
lateRange: 15, lateRange: 15,
allowEarly: true, allowEarly: true,
members: [], members: [],
areaName: '' areaName: ''
}; };
this.isEditMode = false; this.isEditMode = false;
this.selectedGroupId = null; this.selectedGroupId = null;
}, },
// 打开新建考勤组对话框 // 打开新建考勤组对话框
openAddGroupDialog() { openAddGroupDialog() {
this.resetForm(); this.resetForm();
this.showAddGroupModal = true; this.showAddGroupModal = true;
}, },





// 保存考勤组 // 保存考勤组
saveGroup() { saveGroup() {
this.$refs.groupForm.validate(valid => { this.$refs.groupForm.validate(valid => {
if (area) { if (area) {
this.attendanceGroup.areaName = area.name; this.attendanceGroup.areaName = area.name;
} }
if (this.isEditMode) { if (this.isEditMode) {
// 更新现有考勤组 // 更新现有考勤组
const index = this.attendanceGroups.findIndex(g => g.id === this.attendanceGroup.id); const index = this.attendanceGroups.findIndex(g => g.id === this.attendanceGroup.id);
add(newGroup).then((res) => { add(newGroup).then((res) => {
// console.log(res) // console.log(res)
}) })
// 重置表单 // 重置表单
// this.resetForm(); // this.resetForm();
} else { } else {
} }
}); });
}, },
// 取消编辑 // 取消编辑
cancelEdit() { cancelEdit() {
if (this.isEditMode && this.selectedGroupId) { if (this.isEditMode && this.selectedGroupId) {
this.resetForm(); this.resetForm();
} }
}, },
// 搜索用户 // 搜索用户
searchUsers() { searchUsers() {
// 搜索逻辑已在computed属性中实现 // 搜索逻辑已在computed属性中实现
}, },
// 处理迟到开关变化 // 处理迟到开关变化
handleLateChange(value) { handleLateChange(value) {
if (!value) { if (!value) {
this.attendanceGroup.lateRange = 0; this.attendanceGroup.lateRange = 0;
} }
}, },
// 处理早退开关变化 // 处理早退开关变化
handleEarlyChange(value) { handleEarlyChange(value) {
if (!value) { if (!value) {
this.attendanceGroup.earlyRange = 0; this.attendanceGroup.earlyRange = 0;
} }
}, },
// 验证迟到浮动范围 // 验证迟到浮动范围
validateLateRange(value) { validateLateRange(value) {
if (value > 30) { if (value > 30) {
this.$message.warning('迟到浮动范围最大为30分钟'); this.$message.warning('迟到浮动范围最大为30分钟');
} }
}, },
// 显示成功消息 // 显示成功消息
showSuccessMessage(message) { showSuccessMessage(message) {
this.successMessage = message; this.successMessage = message;
this.successMessageVisible = true; this.successMessageVisible = true;
// 3秒后自动关闭 // 3秒后自动关闭
setTimeout(() => { setTimeout(() => {
this.successMessageVisible = false; this.successMessageVisible = false;
} }
}); });
}, },
// 保存区域 // 保存区域
saveArea() { saveArea() {
if (!this.isFormValid) return; if (!this.isFormValid) return;
const newArea = { const newArea = {
id: this.formData.id || Date.now(), // 如果是新建,使用时间戳作为ID id: this.formData.id || Date.now(), // 如果是新建,使用时间戳作为ID
name: this.formData.name.trim(), name: this.formData.name.trim(),
radius: this.formData.radius, radius: this.formData.radius,
enabled: this.formData.enabled enabled: this.formData.enabled
}; };
if (this.formData.id) { if (this.formData.id) {
// 更新现有区域 // 更新现有区域
const index = this.areaList.findIndex(area => area.id === this.formData.id); const index = this.areaList.findIndex(area => area.id === this.formData.id);
}) })
// 重置表单 // 重置表单
this.clearMapSelection(); this.clearMapSelection();
}, },


// 选择考勤组 // 选择考勤组
this.isEditMode = true; this.isEditMode = true;
} }
}, },
// 切换区域状态 // 切换区域状态
toggleAreaStatus(area) { toggleAreaStatus(area) {
if (area.enableStatus == '0') { if (area.enableStatus == '0') {
alert('已启用的区域不允许禁用'); alert('已启用的区域不允许禁用');
return; return;
} }
// 启用区域 // 启用区域
const index = this.areaList.findIndex(a => a.id === area.id); const index = this.areaList.findIndex(a => a.id === area.id);
if (index !== -1) { if (index !== -1) {
// console.log(res) // console.log(res)
}) })
}, },
// 确认删除区域 // 确认删除区域
confirmDeleteArea() { confirmDeleteArea() {
if (!this.currentDeletingArea) return; if (!this.currentDeletingArea) return;
this.areaList = this.areaList.filter( this.areaList = this.areaList.filter(
area => area.id !== this.currentDeletingArea.id area => area.id !== this.currentDeletingArea.id
); );
// console.log(this.currentDeletingArea) // console.log(this.currentDeletingArea)
deleteConfig(this.currentDeletingArea.id).then((res)=> { deleteConfig(this.currentDeletingArea.id).then((res)=> {
// console.log(res) // console.log(res)
}) })
this.currentDeletingArea = null; this.currentDeletingArea = null;
this.showDeleteModal = false; this.showDeleteModal = false;
} }
.main-content { .main-content {
flex-direction: column; flex-direction: column;
} }
.group-list-card, .group-form-card { .group-list-card, .group-form-card {
width: 100%; width: 100%;
} }
.content-wrapper { .content-wrapper {
flex-direction: column; flex-direction: column;
} }
.area-list, .area-list,
.map-section { .map-section {
min-width: auto; min-width: auto;
.control-group { .control-group {
min-width: 100%; min-width: 100%;
} }
.area-table th, .area-table th,
.area-table td { .area-table td {
padding: 8px 5px; padding: 8px 5px;
font-size: 14px; font-size: 14px;
} }
.btn-edit, .btn-edit,
.btn-status, .btn-status,
.btn-delete { .btn-delete {

Loading…
Cancel
Save