浏览代码

修改组页面

master
父节点
当前提交
d2cfd0cfb9
共有 1 个文件被更改,包括 438 次插入258 次删除
  1. 438
    258
      src/views/daka/attendanceteam/index.vue

+ 438
- 258
src/views/daka/attendanceteam/index.vue 查看文件

@@ -2,7 +2,7 @@
<div class="attendance-group-container">
<div class="page-header">
<el-row>
<el-col :span=24>
<el-col :span="24">
<h1>考勤组配置</h1>
<p>设置考勤规则、关联员工和打卡区域</p>
</el-col>
@@ -11,169 +11,210 @@
<div class="main-content">
<el-row :gutter="20">
<!-- 左侧:考勤组列表 -->
<el-col :sm="24" :md="6">
<el-table :data="attendanceGroupData">
<el-table-column label="考勤组" align="center" prop="name" lable-size="100px"></el-table-column>
<el-table-column label="描述" align="center" prop="description" ></el-table-column>
<el-table-column label="考勤时间" align="center" prop="workDays" ></el-table-column>
</el-table>
<el-card class="group-list-card">
<template #header>
<div class="card-header">
<h3>考勤组列表</h3>
<el-button type="primary" size="small" @click="showAddGroupModal = true">
<i class="el-icon-plus"></i> 新建
</el-button>
</div>
</template>
<div class="group-list">
<div
v-for="group in attendanceGroups"
:key="group.id"
class="group-item"
:class="{'active': selectedGroupId === group.id}"
@click="selectGroup(group.id)"
>
<div class="group-name">{{ group.name }}</div>
<div class="group-desc">{{ group.description || '未设置描述' }}</div>
<div class="group-meta">
<span>{{ group.members.length }}名员工</span>
<span v-if="group.areaName">· {{ group.areaName }}</span>
</div>
</div>
<div v-if="attendanceGroups.length === 0" class="empty-state">
<i class="el-icon-s-empty"></i>
<p>暂无考勤组,点击"新建"按钮创建</p>
</div>
</div>
</el-card>
</el-col>
<!-- 右侧:考勤组表单 -->
<el-col :sm="24" :md="18">
<div class="card-header">
<el-card class="group-form-card">
<template #header>
<div class="card-header">
<h3>{{ isEditMode ? '编辑考勤组' : '新建考勤组' }}</h3>
</div>
</template>
<el-card class="group-form-card">
<template #header>
<div class="card-header">
<h3>{{ isEditMode ? '编辑考勤组' : '新建考勤组' }}</h3>
</div>
</template>
<el-form :model="attendanceGroup" :rules="rules" ref="groupForm" label-width="120px">
<!-- 基本信息 -->
<el-form-item label="考勤组名称" prop="name">
<el-input v-model="attendanceGroup.name" placeholder="请输入考勤组名称"></el-input>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input v-model="attendanceGroup.description" placeholder="请输入描述信息"></el-input>
</el-form-item>
<!-- 考勤时间设置 -->
<el-form-item label="工作日设置">
<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-group>
</el-form-item>
<el-form-item label="上班时间" prop="workStartTime">
<el-time-picker
v-model="attendanceGroup.workStartTime"
format="HH:mm"
value-format="HH:mm"
placeholder="选择上班时间"
></el-time-picker>
</el-form-item>
<el-form-item label="迟到浮动" prop="lateRange">
<el-col :span="12">
<el-switch
v-model="attendanceGroup.allowLate"
active-text="允许"
inactive-text="不允许"
@change="handleLateChange"
></el-switch>
</el-col>
<el-col :span="12" v-if="attendanceGroup.allowLate">
<el-slider
v-model="attendanceGroup.lateRange"
:min="1"
:max="30"
:step="1"
show-tooltip
@change="validateLateRange"
></el-slider>
<div class="slider-value">{{ attendanceGroup.lateRange }}分钟</div>
</el-col>
</el-form-item>
<el-form :model="attendanceGroup" :rules="rules" ref="groupForm" label-width="120px">
<!-- 基本信息 -->
<el-form-item label="考勤组名称" prop="name">
<el-input v-model="attendanceGroup.name" placeholder="请输入考勤组名称"></el-input>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input v-model="attendanceGroup.description" placeholder="请输入描述信息"></el-input>
</el-form-item>
<!-- 考勤时间设置 -->
<el-form-item label="工作日设置">
<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-group>
</el-form-item>
<el-form-item label="上班时间" prop="workStartTime">
<el-time-picker
v-model="attendanceGroup.workStartTime"
format="HH:mm"
value-format="HH:mm"
placeholder="选择上班时间"
></el-time-picker>
</el-form-item>
<el-form-item label="迟到浮动" prop="lateRange">
<el-col :span="12">
<el-switch
v-model="attendanceGroup.allowLate"
active-text="允许"
inactive-text="不允许"
@change="handleLateChange"
></el-switch>
</el-col>
<el-col :span="12" v-if="attendanceGroup.allowLate">
<el-slider
v-model="attendanceGroup.lateRange"
:min="1"
:max="30"
:step="1"
show-tooltip
@change="validateLateRange"
></el-slider>
<div class="slider-value">{{ attendanceGroup.lateRange }}分钟</div>
</el-col>
</el-form-item>
<el-form-item label="下班时间" prop="workEndTime">
<el-time-picker
v-model="attendanceGroup.workEndTime"
format="HH:mm"
value-format="HH:mm"
placeholder="选择下班时间"
></el-time-picker>
</el-form-item>
<el-form-item label="早退浮动" prop="earlyRange">
<el-col :span="12">
<el-switch
v-model="attendanceGroup.allowEarly"
active-text="允许"
inactive-text="不允许"
@change="handleEarlyChange"
></el-switch>
</el-col>
<el-col :span="12" v-if="attendanceGroup.allowEarly">
<el-slider
v-model="attendanceGroup.earlyRange"
:min="1"
:max="30"
:step="1"
show-tooltip
@change="validateEarlyRange"
></el-slider>
<div class="slider-value">{{ attendanceGroup.earlyRange }}分钟</div>
</el-col>
</el-form-item>
<!-- 打卡配置 -->
<el-form-item label="打卡区域" prop="areaId">
<el-select
v-model="attendanceGroup.areaId"
placeholder="请选择打卡区域"
>
<el-option
v-for="area in checkInAreas"
:key="area.id"
:label="area.name"
:value="area.id"
></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="打卡方式" prop="checkInType">
<el-radio-group v-model="attendanceGroup.checkInType">
<el-radio label="location">位置打卡</el-radio>
<el-radio label="qr">二维码打卡</el-radio>
<el-radio label="both">两者都可</el-radio>
</el-radio-group>
</el-form-item> -->
<!-- 关联员工 -->
<el-form-item label="关联员工">
<el-button
type="primary"
size="small"
@click="openUserSelectionDialog"
>
<i class="el-icon-plus"></i> 选择员工
</el-button>
<el-table
:data="attendanceGroup.members"
style="width: 100%; margin-top: 20px"
empty-text="暂无关联员工"
>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="employeeId" label="工号"></el-table-column>
<el-table-column prop="department" label="部门"></el-table-column>
<el-table-column prop="position" label="职位"></el-table-column>
<el-table-column label="操作" width="80">
<template #default="scope">
<el-button
type="danger"
size="mini"
@click="removeMember(scope.row)"
>
<i class="el-icon-delete"></i>
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<!-- 操作按钮 -->
<el-form-item>
<el-button type="primary" @click="saveGroup">保存</el-button>
<el-button @click="cancelEdit">取消</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
<el-form-item label="下班时间" prop="workEndTime">
<el-time-picker
v-model="attendanceGroup.workEndTime"
format="HH:mm"
value-format="HH:mm"
placeholder="选择下班时间"
></el-time-picker>
</el-form-item>
<el-form-item label="早退浮动" prop="earlyRange">
<el-col :span="12">
<el-switch
v-model="attendanceGroup.allowEarly"
active-text="允许"
inactive-text="不允许"
@change="handleEarlyChange"
></el-switch>
</el-col>
<el-col :span="12" v-if="attendanceGroup.allowEarly">
<el-slider
v-model="attendanceGroup.earlyRange"
:min="1"
:max="30"
:step="1"
show-tooltip
@change="validateEarlyRange"
></el-slider>
<div class="slider-value">{{ attendanceGroup.earlyRange }}分钟</div>
</el-col>
</el-form-item>
<!-- 打卡配置 -->
<el-form-item label="打卡区域" prop="areaId">
<el-select
v-model="attendanceGroup.areaId"
placeholder="请选择打卡区域"
>
<el-option
v-for="area in checkInAreas"
:key="area.id"
:label="area.name"
:value="area.id"
></el-option>
</el-select>
</el-form-item>
<!-- 关联员工 -->
<el-form-item label="关联员工">
<el-button
type="primary"
size="small"
@click="openUserSelectionDialog"
>
<i class="el-icon-plus"></i> 选择员工
</el-button>
<el-table
:data="attendanceGroup.members"
style="width: 100%; margin-top: 20px"
empty-text="暂无关联员工"
>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="employeeId" label="工号"></el-table-column>
<el-table-column prop="department" label="部门"></el-table-column>
<el-table-column prop="position" label="职位"></el-table-column>
<el-table-column label="操作" width="80">
<template #default="scope">
<el-button
type="danger"
size="mini"
@click="removeMember(scope.row)"
>
<i class="el-icon-delete"></i>
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<!-- 操作按钮 -->
<el-form-item>
<el-button type="primary" @click="saveGroup">保存</el-button>
<el-button @click="cancelEdit">取消</el-button>
</el-form-item>
</el-form>
</el-card>
</el-col>
</el-row>
</div>
<!-- 新建考勤组对话框 -->
<el-dialog
title="新建考勤组"
:visible.sync="showAddGroupModal"
width="30%"
:before-close="handleCloseAddGroupDialog"
>
<el-form :model="newGroup" :rules="newGroupRules" ref="newGroupForm" label-width="100px">
<el-form-item label="考勤组名称" prop="name">
<el-input v-model="newGroup.name" placeholder="请输入考勤组名称"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="newGroup.description" placeholder="请输入描述信息"></el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showAddGroupModal = false">取消</el-button>
<el-button type="primary" @click="createNewGroup">创建</el-button>
</template>
</el-dialog>
<!-- 员工选择对话框 -->
<el-dialog
title="选择员工"
@@ -181,41 +222,15 @@
width="60%"
:before-close="handleCloseUserDialog"
>
<!-- <template #content>
<div class="search-container">
<el-input
v-model="userSearchKeyword"
placeholder="搜索员工"
prefix-icon="el-icon-search"
@keyup.enter="searchUsers"
></el-input>
<el-button @click="searchUsers">搜索</el-button>
</div>
<el-table
:data="filteredUsers"
@selection-change="handleUserSelectionChange"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="employeeId" label="工号"></el-table-column>
<el-table-column prop="department" label="部门"></el-table-column>
<el-table-column prop="position" label="职位"></el-table-column>
</el-table>
</template> -->
<template #footer>
<el-button @click="userSelectionDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmUserSelection">确定</el-button>
</template>
<div class="search-container">
<el-input
v-model="userSearchKeyword"
placeholder="搜索员工"
prefix-icon="el-icon-search"
@keyup.enter="searchUsers"
></el-input>
<el-button @click="searchUsers">搜索</el-button>
</div>
<el-input
v-model="userSearchKeyword"
placeholder="搜索员工"
prefix-icon="el-icon-search"
@keyup.enter="searchUsers"
></el-input>
<el-button @click="searchUsers">搜索</el-button>
</div>
<el-table
:data="filteredUsers"
@selection-change="handleUserSelectionChange"
@@ -226,25 +241,31 @@
<el-table-column prop="department" label="部门"></el-table-column>
<el-table-column prop="position" label="职位"></el-table-column>
</el-table>
<template #footer>
<el-button @click="userSelectionDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmUserSelection">确定</el-button>
</template>
</el-dialog>

</div>
</template>

<script>
import {
add,
getOperationWarnresult,
delOperationWarnresult,
addOperationWarnresult,
updateOperationWarnresult
getList,
update,
del
} from '@/api/daka/attendance-group'

export default {
name: 'AttendanceGroup',
data() {
return {
// 考勤组数据
// 考勤组列表
attendanceGroups: [],
// 当前选中的考勤组ID
selectedGroupId: null,
// 考勤组表单数据
attendanceGroup: {
id: null,
name: '',
@@ -258,9 +279,9 @@ export default {
earlyRange: 15,
areaId: null,
checkInType: 'location',
members: []
members: [],
areaName: ''
},
// 工作日选项
workDays: [
{ value: 'mon', label: '周一' },
@@ -271,22 +292,26 @@ export default {
{ value: 'sat', label: '周六' },
{ value: 'sun', label: '周日' }
],
// 员工列表
users: [],
// 打卡区域列表
checkInAreas: [],
// 新建考勤组表单
newGroup: {
name: '',
description: ''
},
// 新建考勤组表单规则
newGroupRules: {
name: [{ required: true, message: '请输入考勤组名称', trigger: 'blur' }]
},
// 搜索关键词
userSearchKeyword: '',
// 选中的用户
selectedUsers: [],
// 对话框状态
userSelectionDialogVisible: false,
showAddGroupModal: false,
// 表单验证规则
rules: {
name: [
@@ -302,20 +327,16 @@ export default {
{ required: true, message: '请选择打卡区域', trigger: 'change' }
]
},
// 编辑模式
isEditMode: false,
// 提示信息
successMessage: '',
successMessageVisible: false,
attendanceGroupData: [{name: 'sssss', description: 'dddd', workDays: '[mon, tue, wed, thu, fri]'}]
successMessageVisible: false
};
},
computed: {
// 过滤后的用户列表
filteredUsers() {
debugger
// 获取不在当前考勤组中的用户
const groupMemberIds = this.attendanceGroup.members.map(member => member.id);
const availableUsers = this.users.filter(user =>
@@ -337,13 +358,52 @@ export default {
mounted() {
// 加载模拟数据
this.loadMockData();
// 默认进入新建模式
this.resetForm();
// 加载打卡区域数据(实际项目中从API获取)
this.loadCheckInAreas();
},
methods: {
// 加载模拟数据
loadMockData() {
// 模拟考勤组数据
this.attendanceGroups = [
{
id: 1,
name: '研发部考勤组',
description: '研发部门日常考勤规则',
workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
workStartTime: '09:00',
workEndTime: '18:00',
allowLate: true,
lateRange: 15,
allowEarly: true,
earlyRange: 15,
areaId: 1,
areaName: '总部办公楼',
members: [
{ id: 1, name: '张三', employeeId: 'EMP001', department: '研发部', position: '高级工程师' },
{ id: 2, name: '李四', employeeId: 'EMP002', department: '研发部', position: '产品经理' }
]
},
{
id: 2,
name: '销售部考勤组',
description: '销售部门考勤规则',
workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
workStartTime: '09:30',
workEndTime: '18:30',
allowLate: true,
lateRange: 10,
allowEarly: false,
earlyRange: 0,
areaId: 2,
areaName: '销售办公室',
members: [
{ id: 3, name: '王五', employeeId: 'EMP003', department: '销售部', position: '销售代表' },
{ id: 4, name: '赵六', employeeId: 'EMP004', department: '销售部', position: '销售经理' }
]
}
];
// 模拟员工数据
this.users = [
{ id: 1, name: '张三', employeeId: 'EMP001', department: '研发部', position: '高级工程师' },
@@ -357,8 +417,10 @@ export default {
{ id: 9, name: '郑十一', employeeId: 'EMP009', department: '市场部', position: '市场专员' },
{ id: 10, name: '王十二', employeeId: 'EMP010', department: '市场部', position: '市场总监' }
];
// 模拟打卡区域数据
},
// 加载打卡区域数据(实际项目中从API获取)
loadCheckInAreas() {
this.checkInAreas = [
{ id: 1, name: '总部办公楼', lng: 116.404, lat: 39.915, radius: 300, enabled: true },
{ id: 2, name: '销售办公室', lng: 116.414, lat: 39.905, radius: 200, enabled: true },
@@ -366,6 +428,17 @@ export default {
];
},
// 选择考勤组
selectGroup(id) {
this.selectedGroupId = id;
const group = this.attendanceGroups.find(g => g.id === id);
if (group) {
// 复制考勤组数据
this.attendanceGroup = { ...group };
this.isEditMode = true;
}
},
// 重置表单
resetForm() {
this.attendanceGroup = {
@@ -381,56 +454,91 @@ export default {
earlyRange: 15,
areaId: null,
checkInType: 'location',
members: []
members: [],
areaName: ''
};
this.isEditMode = false;
this.selectedGroupId = null;
},
// 打开编辑模式(示例:编辑第一个考勤组)
openEditMode() {
// 实际项目中,这里应该接收考勤组ID并从API获取数据
// 这里仅作示例,使用模拟数据
const exampleGroup = {
id: 1,
name: '研发部考勤组',
description: '研发部门日常考勤规则',
workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
workStartTime: '09:00',
workEndTime: '18:00',
allowLate: true,
lateRange: 15,
allowEarly: true,
earlyRange: 15,
areaId: 1,
checkInType: 'location',
members: this.users.slice(0, 2)
};
this.attendanceGroup = { ...exampleGroup };
this.isEditMode = true;
// 打开新建考勤组对话框
openAddGroupDialog() {
this.resetForm();
this.showAddGroupModal = true;
},
// 创建新考勤组
createNewGroup() {
this.$refs.newGroupForm.validate(valid => {
if (valid) {
// 实际项目中调用API创建
const newGroup = {
name: this.newGroup.name,
description: this.newGroup.description,
workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
workStartTime: '09:00',
workEndTime: '18:00',
allowLate: true,
lateRange: 15,
allowEarly: true,
earlyRange: 15,
areaId: null,
areaName: '',
members: []
};
add(newGroup).then((res) => {
console.log(res)
})
this.attendanceGroups.push(newGroup);
this.selectGroup(newGroup.id);
this.showAddGroupModal = false;
this.$message.success('考勤组创建成功');
}
});
},
// 处理关闭新建考勤组对话框
handleCloseAddGroupDialog(done) {
if (this.newGroup.name) {
this.$confirm('确定要取消创建吗?', '提示', {
type: 'warning'
}).then(() => {
done();
}).catch(() => {
// 取消关闭
});
} else {
done();
}
},
// 保存考勤组
saveGroup() {
this.$refs.groupForm.validate(valid => {
if (valid) {
// 这里应该调用API保存数据
// 示例代码仅做演示
this.attendanceGroup.workDaysList = this.attendanceGroup.workDays
// 查找打卡区域名称
const area = this.checkInAreas.find(a => a.id === this.attendanceGroup.areaId);
if (area) {
this.attendanceGroup.areaName = area.name;
}
if (this.isEditMode) {
console.log('更新考勤组:', this.attendanceGroup);
this.showSuccessMessage('考勤组更新成功');
// 更新现有考勤组
const index = this.attendanceGroups.findIndex(g => g.id === this.attendanceGroup.id);
if (index !== -1) {
this.attendanceGroups.splice(index, 1, this.attendanceGroup);
}
this.$message.success('考勤组更新成功');
} else {
console.log('创建考勤组:', this.attendanceGroup);
this.showSuccessMessage('考勤组创建成功');
add(this.attendanceGroup).then((res) => {
console.log(res)
})
// 添加新考勤组
this.attendanceGroups.push(this.attendanceGroup);
this.selectedGroupId = this.attendanceGroup.id;
this.$message.success('考勤组创建成功');
}
// 重置表单
this.resetForm();
// this.resetForm();
} else {
console.log('表单验证失败');
return false;
@@ -440,7 +548,14 @@ export default {
// 取消编辑
cancelEdit() {
this.resetForm();
if (this.isEditMode && this.selectedGroupId) {
const group = this.attendanceGroups.find(g => g.id === this.selectedGroupId);
if (group) {
this.attendanceGroup = { ...group };
}
} else {
this.resetForm();
}
},
// 打开员工选择对话框
@@ -457,7 +572,6 @@ export default {
// 搜索用户
searchUsers() {
// 搜索逻辑已在computed属性中实现
// 这里只需触发重新计算
},
// 确认选择员工
@@ -549,10 +663,6 @@ export default {
</script>

<style scoped>
.equal-width .left, .equal-width .right {
flex: 1;
}

.attendance-group-container {
padding: 20px;
}
@@ -572,12 +682,11 @@ export default {
}

.main-content {
display: flex;
max-width: 800px;
max-width: 1200px;
margin: 0 auto;
}

.group-form-card {
.group-list-card, .group-form-card {
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
@@ -627,4 +736,75 @@ export default {
.el-message {
top: 80px;
}
</style>

/* 考勤组列表样式 */
.group-list {
max-height: 400px;
overflow-y: auto;
padding: 10px 0;
}

.group-item {
padding: 15px;
margin-bottom: 10px;
border-radius: 4px;
cursor: pointer;
background-color: #fff;
border: 1px solid #ebeef5;
transition: all 0.3s;
}

.group-item:hover {
border-color: #409eff;
background-color: #f5f7fa;
}

.group-item.active {
border-color: #409eff;
background-color: #ecf5ff;
}

.group-name {
font-weight: 500;
margin-bottom: 5px;
color: #303133;
}

.group-desc {
font-size: 13px;
color: #606266;
margin-bottom: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.group-meta {
font-size: 12px;
color: #909399;
}

.empty-state {
text-align: center;
padding: 30px 0;
color: #909399;
}

.empty-state i {
font-size: 36px;
margin-bottom: 10px;
display: block;
color: #dcdfe6;
}

/* 响应式布局 */
@media (max-width: 768px) {
.main-content {
flex-direction: column;
}
.group-list-card, .group-form-card {
width: 100%;
}
}
</style>

正在加载...
取消
保存