| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-tabs v-model="activeTab" type="border-card"> |
| | | <el-tabs v-model="activeTab" |
| | | type="border-card"> |
| | | <!-- 假期设置 --> |
| | | <el-tab-pane label="假期设置" name="holiday"> |
| | | <el-tab-pane label="假期设置" |
| | | name="holiday"> |
| | | <div class="tab-content"> |
| | | <el-button type="primary" @click="openDialog('holiday', 'add')">新增假期</el-button> |
| | | |
| | | <el-table :data="holidayData" border style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="name" label="假期名称" /> |
| | | <el-table-column prop="type" label="假期类型"> |
| | | <el-button type="primary" |
| | | @click="openDialog('holiday', 'add')">新增假期</el-button> |
| | | <el-table :data="holidayData" |
| | | border |
| | | style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="name" |
| | | label="假期名称" /> |
| | | <el-table-column prop="type" |
| | | label="假期类型"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getTagType(scope.row.type)">{{ getTypeLabel(scope.row.type) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="startDate" label="开始日期" /> |
| | | <el-table-column prop="endDate" label="结束日期" /> |
| | | <el-table-column prop="days" label="天数" align="center" /> |
| | | <el-table-column prop="status" label="状态" > |
| | | <el-table-column prop="startDate" |
| | | label="开始日期" /> |
| | | <el-table-column prop="endDate" |
| | | label="结束日期" /> |
| | | <el-table-column prop="days" |
| | | label="天数" |
| | | align="center" /> |
| | | <el-table-column prop="status" |
| | | label="状态"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'"> |
| | | {{ scope.row.status === 'active' ? '启用' : '停用' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" fixed="right"> |
| | | <el-table-column label="操作" |
| | | fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" size="small" @click="openDialog('holiday', 'edit', scope.row)">编辑</el-button> |
| | | <el-button type="danger" size="small" @click="deleteItem('holiday', scope.row)">删除</el-button> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="openDialog('holiday', 'edit', scope.row)">编辑</el-button> |
| | | <el-button type="danger" |
| | | size="small" |
| | | @click="deleteItem('holiday', scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-tab-pane> |
| | | |
| | | <!-- 年假设置 --> |
| | | <el-tab-pane label="年假设置" name="annual"> |
| | | <el-tab-pane label="年假设置" |
| | | name="annual"> |
| | | <div class="tab-content"> |
| | | <el-button type="primary" @click="openDialog('annual', 'add')">新增年假规则</el-button> |
| | | |
| | | <el-table :data="annualData" border style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="employeeType" label="员工类型"> |
| | | <el-button type="primary" |
| | | @click="openDialog('annual', 'add')">新增年假规则</el-button> |
| | | <el-table :data="annualData" |
| | | border |
| | | style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="employeeType" |
| | | label="员工类型"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getTagType(scope.row.employeeType)">{{ getTypeLabel(scope.row.employeeType) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="workYears" label="工作年限" /> |
| | | <el-table-column prop="annualDays" label="年假天数" align="center" /> |
| | | <el-table-column prop="maxCarryOver" label="最大结转天数" align="center" /> |
| | | <el-table-column prop="status" label="状态"> |
| | | <el-table-column prop="workYears" |
| | | label="工作年限" /> |
| | | <el-table-column prop="annualDays" |
| | | label="年假天数" |
| | | align="center" /> |
| | | <el-table-column prop="maxCarryOver" |
| | | label="最大结转天数" |
| | | align="center" /> |
| | | <el-table-column prop="status" |
| | | label="状态"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'"> |
| | | {{ scope.row.status === 'active' ? '启用' : '停用' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" fixed="right"> |
| | | <el-table-column label="操作" |
| | | fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" size="small" @click="openDialog('annual', 'edit', scope.row)">编辑</el-button> |
| | | <el-button type="danger" size="small" @click="deleteItem('annual', scope.row)">删除</el-button> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="openDialog('annual', 'edit', scope.row)">编辑</el-button> |
| | | <el-button type="danger" |
| | | size="small" |
| | | @click="deleteItem('annual', scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-tab-pane> |
| | | |
| | | <!-- 加班设置 --> |
| | | <el-tab-pane label="加班设置" name="overtime"> |
| | | <el-tab-pane label="加班设置" |
| | | name="overtime"> |
| | | <div class="tab-content"> |
| | | <el-button type="primary" @click="openDialog('overtime', 'add')">新增加班规则</el-button> |
| | | |
| | | <el-table :data="overtimeData" border style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="name" label="规则名称" /> |
| | | <el-table-column prop="type" label="加班类型" > |
| | | <el-button type="primary" |
| | | @click="openDialog('overtime', 'add')">新增加班规则</el-button> |
| | | <el-table :data="overtimeData" |
| | | border |
| | | style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="name" |
| | | label="规则名称" /> |
| | | <el-table-column prop="type" |
| | | label="加班类型"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getTagType(scope.row.type)">{{ getTypeLabel(scope.row.type) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="startTime" label="开始时间" /> |
| | | <el-table-column prop="endTime" label="结束时间" /> |
| | | <el-table-column prop="rate" label="倍率" align="center" /> |
| | | <el-table-column prop="status" label="状态" > |
| | | <el-table-column prop="startTime" |
| | | label="开始时间" /> |
| | | <el-table-column prop="endTime" |
| | | label="结束时间" /> |
| | | <el-table-column prop="rate" |
| | | label="倍率" |
| | | align="center" /> |
| | | <el-table-column prop="status" |
| | | label="状态"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'"> |
| | | {{ scope.row.status === 'active' ? '启用' : '停用' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" fixed="right"> |
| | | <el-table-column label="操作" |
| | | fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" size="small" @click="openDialog('overtime', 'edit', scope.row)">编辑</el-button> |
| | | <el-button type="danger" size="small" @click="deleteItem('overtime', scope.row)">删除</el-button> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="openDialog('overtime', 'edit', scope.row)">编辑</el-button> |
| | | <el-button type="danger" |
| | | size="small" |
| | | @click="deleteItem('overtime', scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-tab-pane> |
| | | |
| | | <!-- 上班时间设置 --> |
| | | <el-tab-pane label="上班时间设置" name="worktime"> |
| | | <el-tab-pane label="上班时间设置" |
| | | name="worktime"> |
| | | <div class="tab-content"> |
| | | <el-button type="primary" @click="openDialog('worktime', 'add')">新增时间段</el-button> |
| | | |
| | | <el-table :data="worktimeData" border style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="name" label="时间段名称" /> |
| | | <el-table-column prop="startTime" label="上班时间"/> |
| | | <el-table-column prop="endTime" label="下班时间" /> |
| | | <el-table-column prop="flexibleStart" label="弹性上班"> |
| | | <el-button type="primary" |
| | | @click="openDialog('worktime', 'add')">新增时间段</el-button> |
| | | <el-table :data="worktimeData" |
| | | border |
| | | style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="name" |
| | | label="时间段名称" /> |
| | | <el-table-column prop="startTime" |
| | | label="上班时间" /> |
| | | <el-table-column prop="endTime" |
| | | label="下班时间" /> |
| | | <el-table-column prop="flexibleStart" |
| | | label="弹性上班"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.flexibleStart === 'true' ? 'success' : 'info'"> |
| | | {{ scope.row.flexibleStart === 'true' ? '是' : '否' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="flexibleMinutes" label="弹性时间(分钟)" width="120" align="center" /> |
| | | <el-table-column prop="status" label="状态" > |
| | | <el-table-column prop="flexibleMinutes" |
| | | label="弹性时间(分钟)" |
| | | width="120" |
| | | align="center" /> |
| | | <el-table-column prop="status" |
| | | label="状态"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'"> |
| | | {{ scope.row.status === 'active' ? '启用' : '停用' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" fixed="right"> |
| | | <el-table-column label="操作" |
| | | fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" size="small" @click="openDialog('worktime', 'edit', scope.row)">编辑</el-button> |
| | | <el-button type="danger" size="small" @click="deleteItem('worktime', scope.row)">删除</el-button> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="openDialog('worktime', 'edit', scope.row)">编辑</el-button> |
| | | <el-button type="danger" |
| | | size="small" |
| | | @click="deleteItem('worktime', scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-tab-pane> |
| | | |
| | | <!-- 打卡记录 --> |
| | | <el-tab-pane label="打卡记录" name="attendance"> |
| | | <el-tab-pane label="打卡记录" |
| | | name="attendance"> |
| | | <div class="tab-content"> |
| | | <div style="margin-bottom: 20px;"> |
| | | <el-date-picker |
| | | v-model="attendanceDate" |
| | | type="date" |
| | | placeholder="选择日期" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="margin-right: 10px;" |
| | | @change="filterAttendanceData" |
| | | /> |
| | | <el-select |
| | | v-model="attendanceStatus" |
| | | placeholder="选择状态" |
| | | style="width: 120px; margin-right: 10px;" |
| | | @change="filterAttendanceData" |
| | | > |
| | | <el-option label="全部" value="" /> |
| | | <el-option label="正常" value="normal" /> |
| | | <el-option label="迟到" value="late" /> |
| | | <el-option label="早退" value="early" /> |
| | | <el-option label="缺勤" value="absent" /> |
| | | <el-date-picker v-model="attendanceDate" |
| | | type="date" |
| | | placeholder="选择日期" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="margin-right: 10px;" |
| | | @change="filterAttendanceData" /> |
| | | <el-select v-model="attendanceStatus" |
| | | placeholder="选择状态" |
| | | style="width: 120px; margin-right: 10px;" |
| | | @change="filterAttendanceData"> |
| | | <el-option label="全部" |
| | | value="" /> |
| | | <el-option label="正常" |
| | | value="normal" /> |
| | | <el-option label="迟到" |
| | | value="late" /> |
| | | <el-option label="早退" |
| | | value="early" /> |
| | | <el-option label="缺勤" |
| | | value="absent" /> |
| | | </el-select> |
| | | <el-button type="primary" @click="exportAttendance">导出记录</el-button> |
| | | <el-button type="primary" |
| | | @click="exportAttendance">导出记录</el-button> |
| | | </div> |
| | | |
| | | <el-table :data="filteredAttendanceData" border style="width: 100%;"> |
| | | <el-table-column prop="employeeName" label="员工姓名" width="120" /> |
| | | <el-table-column prop="department" label="部门" width="120" /> |
| | | <el-table-column prop="date" label="日期" width="120" /> |
| | | <el-table-column prop="clockInTime" label="上班打卡" width="120" /> |
| | | <el-table-column prop="clockOutTime" label="下班打卡" width="120" /> |
| | | <el-table-column prop="workHours" label="工作时长" width="100" align="center" /> |
| | | <el-table-column prop="status" label="状态" width="100" align="center"> |
| | | <el-table :data="filteredAttendanceData" |
| | | border |
| | | style="width: 100%;"> |
| | | <el-table-column prop="employeeName" |
| | | label="员工姓名" |
| | | width="120" /> |
| | | <el-table-column prop="department" |
| | | label="部门" |
| | | width="120" /> |
| | | <el-table-column prop="date" |
| | | label="日期" |
| | | width="120" /> |
| | | <el-table-column prop="clockInTime" |
| | | label="上班打卡" |
| | | width="120" /> |
| | | <el-table-column prop="clockOutTime" |
| | | label="下班打卡" |
| | | width="120" /> |
| | | <el-table-column prop="workHours" |
| | | label="工作时长" |
| | | width="100" |
| | | align="center" /> |
| | | <el-table-column prop="status" |
| | | label="状态" |
| | | width="100" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getAttendanceTagType(scope.row.status)">{{ getAttendanceStatusLabel(scope.row.status) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="location" label="打卡地点" width="150" /> |
| | | <el-table-column prop="remark" label="备注" min-width="150" /> |
| | | <el-table-column prop="location" |
| | | label="打卡地点" |
| | | width="150" /> |
| | | <el-table-column prop="remark" |
| | | label="备注" |
| | | min-width="150" /> |
| | | </el-table> |
| | | </div> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | |
| | | <!-- 通用弹窗 --> |
| | | <el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px"> |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="100px"> |
| | | <el-form-item label="名称" prop="name" v-if="currentType !== 'annual'"> |
| | | <el-input v-model="form.name" placeholder="请输入名称" /> |
| | | <el-dialog v-model="dialogVisible" |
| | | :title="dialogTitle" |
| | | width="600px"> |
| | | <el-form ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-width="100px"> |
| | | <el-form-item label="名称" |
| | | prop="name" |
| | | v-if="currentType !== 'annual'"> |
| | | <el-input v-model="form.name" |
| | | placeholder="请输入名称" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="类型" prop="type" v-if="currentType === 'holiday' || currentType === 'overtime'"> |
| | | <el-select v-model="form.type" placeholder="请选择类型" style="width: 100%"> |
| | | <el-option |
| | | v-for="option in getTypeOptions()" |
| | | :key="option.value" |
| | | :label="option.label" |
| | | :value="option.value" |
| | | /> |
| | | <el-form-item label="类型" |
| | | prop="type" |
| | | v-if="currentType === 'holiday' || currentType === 'overtime'"> |
| | | <el-select v-model="form.type" |
| | | placeholder="请选择类型" |
| | | style="width: 100%"> |
| | | <el-option v-for="option in getTypeOptions()" |
| | | :key="option.value" |
| | | :label="option.label" |
| | | :value="option.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="员工类型" prop="employeeType" v-if="currentType === 'annual'"> |
| | | <el-select v-model="form.employeeType" placeholder="请选择员工类型" style="width: 100%"> |
| | | <el-form-item label="员工类型" |
| | | prop="employeeType" |
| | | v-if="currentType === 'annual'"> |
| | | <el-select v-model="form.employeeType" |
| | | placeholder="请选择员工类型" |
| | | style="width: 100%"> |
| | | <!-- <el-option label="正式员工" value="regular" /> |
| | | <el-option label="试用期员工" value="probation" /> |
| | | <el-option label="实习生" value="intern" /> --> |
| | | <el-option |
| | | v-for="option in getTypeOptions()" |
| | | :key="option.value" |
| | | :label="option.label" |
| | | :value="option.value" |
| | | /> |
| | | <el-option v-for="option in getTypeOptions()" |
| | | :key="option.value" |
| | | :label="option.label" |
| | | :value="option.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="工作年限" prop="workYears" v-if="currentType === 'annual'"> |
| | | <el-input v-model="form.workYears" placeholder="如:1-3年、3-5年等" /> |
| | | <el-form-item label="工作年限" |
| | | prop="workYears" |
| | | v-if="currentType === 'annual'"> |
| | | <el-input v-model="form.workYears" |
| | | placeholder="如:1-3年、3-5年等" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="年假天数" prop="annualDays" v-if="currentType === 'annual'"> |
| | | <el-input-number v-model="form.annualDays" :min="0" :max="365" style="width: 100%" /> |
| | | <el-form-item label="年假天数" |
| | | prop="annualDays" |
| | | v-if="currentType === 'annual'"> |
| | | <el-input-number v-model="form.annualDays" |
| | | :min="0" |
| | | :max="365" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="最大结转天数" prop="maxCarryOver" v-if="currentType === 'annual'"> |
| | | <el-input-number v-model="form.maxCarryOver" :min="0" :max="30" style="width: 100%" /> |
| | | <el-form-item label="最大结转天数" |
| | | prop="maxCarryOver" |
| | | v-if="currentType === 'annual'"> |
| | | <el-input-number v-model="form.maxCarryOver" |
| | | :min="0" |
| | | :max="30" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="日期范围" prop="dateRange" v-if="currentType === 'holiday'"> |
| | | <el-date-picker |
| | | v-model="form.dateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | style="width: 100%" |
| | | @change="calculateDays" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="天数" prop="days" v-if="currentType === 'holiday'"> |
| | | <el-input-number v-model="form.days" :min="0" style="width: 100%" /> |
| | | <el-form-item label="日期范围" |
| | | prop="dateRange" |
| | | v-if="currentType === 'holiday'"> |
| | | <el-date-picker v-model="form.dateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | style="width: 100%" |
| | | @change="calculateDays" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="开始时间" prop="startTime" v-if="currentType === 'overtime'"> |
| | | <el-time-picker |
| | | v-model="form.startTime" |
| | | placeholder="开始时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | @change="validateTimeField('startTime')" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="结束时间" prop="endTime" v-if="currentType === 'overtime'"> |
| | | <el-time-picker |
| | | v-model="form.endTime" |
| | | placeholder="结束时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | @change="validateTimeField('endTime')" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="倍率" prop="rate" v-if="currentType === 'overtime'"> |
| | | <el-input-number v-model="form.rate" :min="1" :max="3" :step="0.5" style="width: 100%" /> |
| | | <el-form-item label="天数" |
| | | prop="days" |
| | | v-if="currentType === 'holiday'"> |
| | | <el-input-number v-model="form.days" |
| | | :min="0" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="上班时间" prop="workStartTime" v-if="currentType === 'worktime'"> |
| | | <el-time-picker |
| | | v-model="form.workStartTime" |
| | | placeholder="上班时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | @change="validateTimeField('workStartTime')" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="下班时间" prop="workEndTime" v-if="currentType === 'worktime'"> |
| | | <el-time-picker |
| | | v-model="form.workEndTime" |
| | | placeholder="下班时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | @change="validateTimeField('workEndTime')" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="弹性上班" prop="flexibleStart" v-if="currentType === 'worktime'"> |
| | | <el-form-item label="开始时间" |
| | | prop="startTime" |
| | | v-if="currentType === 'overtime'"> |
| | | <el-time-picker v-model="form.startTime" |
| | | placeholder="开始时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | @change="validateTimeField('startTime')" /> |
| | | </el-form-item> |
| | | <el-form-item label="结束时间" |
| | | prop="endTime" |
| | | v-if="currentType === 'overtime'"> |
| | | <el-time-picker v-model="form.endTime" |
| | | placeholder="结束时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | @change="validateTimeField('endTime')" /> |
| | | </el-form-item> |
| | | <el-form-item label="倍率" |
| | | prop="rate" |
| | | v-if="currentType === 'overtime'"> |
| | | <el-input-number v-model="form.rate" |
| | | :min="1" |
| | | :max="3" |
| | | :step="0.5" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="上班时间" |
| | | prop="workStartTime" |
| | | v-if="currentType === 'worktime'"> |
| | | <el-time-picker v-model="form.workStartTime" |
| | | placeholder="上班时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | @change="validateTimeField('workStartTime')" /> |
| | | </el-form-item> |
| | | <el-form-item label="下班时间" |
| | | prop="workEndTime" |
| | | v-if="currentType === 'worktime'"> |
| | | <el-time-picker v-model="form.workEndTime" |
| | | placeholder="下班时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 100%" |
| | | @change="validateTimeField('workEndTime')" /> |
| | | </el-form-item> |
| | | <el-form-item label="弹性上班" |
| | | prop="flexibleStart" |
| | | v-if="currentType === 'worktime'"> |
| | | <el-switch v-model="form.flexibleStart" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="弹性时间(分钟)" prop="flexibleMinutes" v-if="currentType === 'worktime' && form.flexibleStart"> |
| | | <el-input-number v-model="form.flexibleMinutes" :min="0" :max="120" style="width: 100%" /> |
| | | <el-form-item label="弹性时间(分钟)" |
| | | prop="flexibleMinutes" |
| | | v-if="currentType === 'worktime' && form.flexibleStart"> |
| | | <el-input-number v-model="form.flexibleMinutes" |
| | | :min="0" |
| | | :max="120" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="状态" prop="status"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio value="active">启用</el-radio> |
| | | <el-radio value="inactive">停用</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="状态" |
| | | prop="status"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio value="active">启用</el-radio> |
| | | <el-radio value="inactive">停用</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitForm">确定</el-button> |
| | | <el-button @click="dialogVisible = false">取消</el-button> |
| | | <el-button type="primary" @click="submitForm">确定</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, onUnmounted } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { listHolidaySettings, addHolidaySettings, updateHolidaySettings, delHolidaySettings, listAnnualLeaveSettingList, addAnnualLeaveSetting, updateAnnualLeaveSetting, delAnnualLeaveSetting, listOvertimeSettingList, addOvertimeSetting, updateOvertimeSetting, delOvertimeSetting, listWorkingHoursSettingList, addWorkingHoursSetting, updateWorkingHoursSetting, delWorkingHoursSetting } from '@/api/collaborativeApproval/attendanceManagement.js' |
| | | import { ref, reactive, onMounted, onUnmounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { |
| | | listHolidaySettings, |
| | | addHolidaySettings, |
| | | updateHolidaySettings, |
| | | delHolidaySettings, |
| | | listAnnualLeaveSettingList, |
| | | addAnnualLeaveSetting, |
| | | updateAnnualLeaveSetting, |
| | | delAnnualLeaveSetting, |
| | | listOvertimeSettingList, |
| | | addOvertimeSetting, |
| | | updateOvertimeSetting, |
| | | delOvertimeSetting, |
| | | listWorkingHoursSettingList, |
| | | addWorkingHoursSetting, |
| | | updateWorkingHoursSetting, |
| | | delWorkingHoursSetting, |
| | | } from "@/api/collaborativeApproval/attendanceManagement.js"; |
| | | |
| | | // 当前激活的标签页 |
| | | const activeTab = ref('holiday') |
| | | // 当前激活的标签页 |
| | | const activeTab = ref("holiday"); |
| | | |
| | | // 弹窗相关 |
| | | const dialogVisible = ref(false) |
| | | const dialogTitle = ref('') |
| | | const currentType = ref('') |
| | | const currentAction = ref('') |
| | | const currentEditId = ref('') |
| | | const formRef = ref() |
| | | const page = { |
| | | // 弹窗相关 |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const currentType = ref(""); |
| | | const currentAction = ref(""); |
| | | const currentEditId = ref(""); |
| | | const formRef = ref(); |
| | | const page = { |
| | | current: 1, |
| | | size: 20, |
| | | total: 0, |
| | | } |
| | | const holidayData = ref([]) |
| | | const annualData = ref([]) |
| | | const overtimeData = ref([]) |
| | | const worktimeData = ref([]) |
| | | }; |
| | | const holidayData = ref([]); |
| | | const annualData = ref([]); |
| | | const overtimeData = ref([]); |
| | | const worktimeData = ref([]); |
| | | |
| | | // 打卡记录相关数据 |
| | | const attendanceData = ref([]) |
| | | const filteredAttendanceData = ref([]) |
| | | const attendanceDate = ref('') |
| | | const attendanceStatus = ref('') |
| | | // 打卡记录相关数据 |
| | | const attendanceData = ref([]); |
| | | const filteredAttendanceData = ref([]); |
| | | const attendanceDate = ref(""); |
| | | const attendanceStatus = ref(""); |
| | | |
| | | // 表单数据 |
| | | const form = reactive({ |
| | | name: '', |
| | | type: '', |
| | | dateRange: [], |
| | | startDate: '', |
| | | endDate: '', |
| | | days: 0, |
| | | employeeType: '', |
| | | workYears: '', |
| | | annualDays: 0, |
| | | maxCarryOver: 0, |
| | | startTime: '', // 加班开始时间 |
| | | endTime: '', // 加班结束时间 |
| | | workStartTime: '', // 上班时间 |
| | | workEndTime: '', // 下班时间 |
| | | rate: 1.5, |
| | | flexibleStart: false, |
| | | flexibleMinutes: 30, |
| | | status: 'active' |
| | | }) |
| | | |
| | | // 表单验证规则 |
| | | const rules = { |
| | | name: [{ required: true, message: '请输入名称', trigger: 'blur' }], |
| | | type: [{ required: true, message: '请选择类型', trigger: 'change' }], |
| | | dateRange: [{ required: true, message: '请选择日期范围', trigger: 'change' }], |
| | | days: [{ required: true, message: '请输入天数', trigger: 'blur' }], |
| | | employeeType: [{ required: true, message: '请选择员工类型', trigger: 'change' }], |
| | | workYears: [{ required: true, message: '请输入工作年限', trigger: 'blur' }], |
| | | annualDays: [{ required: true, message: '请输入年假天数', trigger: 'blur' }], |
| | | maxCarryOver: [{ required: true, message: '请输入最大结转天数', trigger: 'blur' }], |
| | | startTime: [{ |
| | | required: true, |
| | | message: '请选择开始时间', |
| | | trigger: 'change', |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error('请选择开始时间')) |
| | | } else { |
| | | callback() |
| | | } |
| | | } |
| | | }], |
| | | endTime: [{ |
| | | required: true, |
| | | message: '请选择结束时间', |
| | | trigger: 'change', |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error('请选择结束时间')) |
| | | } else { |
| | | callback() |
| | | } |
| | | } |
| | | }], |
| | | workStartTime: [{ |
| | | required: true, |
| | | message: '请选择上班时间', |
| | | trigger: 'change', |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error('请选择上班时间')) |
| | | } else { |
| | | callback() |
| | | } |
| | | } |
| | | }], |
| | | workEndTime: [{ |
| | | required: true, |
| | | message: '请选择下班时间', |
| | | trigger: 'change', |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error('请选择下班时间')) |
| | | } else { |
| | | callback() |
| | | } |
| | | } |
| | | }], |
| | | rate: [{ required: true, message: '请输入倍率', trigger: 'blur' }] |
| | | } |
| | | // 工具函数 |
| | | const getTagType = (type) => { |
| | | const tagMap = { |
| | | legal: 'success', adjustment: 'warning', special: 'info', company: 'primary', |
| | | weekday: 'primary', weekend: 'warning', holiday: 'danger', night: 'info', |
| | | regular: 'success', probation: 'info', intern: 'danger' |
| | | } |
| | | return tagMap[type] || 'info' |
| | | } |
| | | |
| | | const getTypeLabel = (type) => { |
| | | const labelMap = { |
| | | legal: '法定节假日', adjustment: '调休日', special: '特殊假期', company: '公司假期', |
| | | weekday: '工作日加班', weekend: '周末加班', holiday: '节假日加班', night: '深夜加班', |
| | | regular: '正式员工', probation: '试用期员工', intern: '实习生' |
| | | } |
| | | return labelMap[type] || type |
| | | } |
| | | |
| | | // 打卡记录相关工具函数 |
| | | const getAttendanceTagType = (status) => { |
| | | const tagMap = { |
| | | normal: 'success', |
| | | late: 'warning', |
| | | early: 'warning', |
| | | absent: 'danger' |
| | | } |
| | | return tagMap[status] || 'info' |
| | | } |
| | | |
| | | const getAttendanceStatusLabel = (status) => { |
| | | const labelMap = { |
| | | normal: '正常', |
| | | late: '迟到', |
| | | early: '早退', |
| | | absent: '缺勤' |
| | | } |
| | | return labelMap[status] || status |
| | | } |
| | | |
| | | const getTypeOptions = () => { |
| | | if (currentType.value === 'holiday') { |
| | | return [ |
| | | { label: '法定节假日', value: 'legal' }, |
| | | { label: '调休日', value: 'adjustment' }, |
| | | { label: '特殊假期', value: 'special' }, |
| | | { label: '公司假期', value: 'company' } |
| | | ] |
| | | } else if (currentType.value === 'overtime') { |
| | | return [ |
| | | { label: '工作日加班', value: 'weekday' }, |
| | | { label: '周末加班', value: 'weekend' }, |
| | | { label: '节假日加班', value: 'holiday' }, |
| | | { label: '深夜加班', value: 'night' } |
| | | ] |
| | | } else if (currentType.value === 'annual') { |
| | | return [ |
| | | { label: '正式员工', value: 'regular' }, |
| | | { label: '试用期员工', value: 'probation' }, |
| | | { label: '实习生', value: 'intern' } |
| | | ] |
| | | } |
| | | return [] |
| | | } |
| | | |
| | | // 计算假期天数 |
| | | const calculateDays = () => { |
| | | try { |
| | | if (form.dateRange && form.dateRange.length === 2 && form.dateRange[0] && form.dateRange[1]) { |
| | | const start = new Date(form.dateRange[0]) |
| | | const end = new Date(form.dateRange[1]) |
| | | form.startDate = start.toISOString().split('T')[0] |
| | | form.endDate = end.toISOString().split('T')[0] |
| | | |
| | | if (isNaN(start.getTime()) || isNaN(end.getTime())) { |
| | | console.warn('无效的日期格式') |
| | | return |
| | | } |
| | | |
| | | const diffTime = Math.abs(end - start) |
| | | const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1 |
| | | form.days = diffDays |
| | | } |
| | | } catch (error) { |
| | | console.error('计算天数失败:', error) |
| | | } |
| | | } |
| | | |
| | | // 验证时间格式 |
| | | // const validateTime = (time) => { |
| | | // if (!time) return '' |
| | | // if (typeof time === 'string') return time |
| | | // if (time instanceof Date) { |
| | | // return time.toTimeString().slice(0, 5) |
| | | // } |
| | | // return '' |
| | | // } |
| | | |
| | | // 验证时间字段 |
| | | const validateTimeField = (fieldName) => { |
| | | try { |
| | | const value = form[fieldName] |
| | | if (value && typeof value === 'object' && value.hour !== undefined) { |
| | | // 如果是时间对象,转换为字符串格式 |
| | | const hours = value.hour.toString().padStart(2, '0') |
| | | const minutes = value.minute.toString().padStart(2, '0') |
| | | form[fieldName] = `${hours}:${minutes}` |
| | | } |
| | | } catch (error) { |
| | | console.error(`验证时间字段 ${fieldName} 失败:`, error) |
| | | form[fieldName] = '' |
| | | } |
| | | } |
| | | |
| | | // 打开弹窗 |
| | | const openDialog = (type, action, row = null) => { |
| | | try { |
| | | currentType.value = type |
| | | currentAction.value = action |
| | | |
| | | if (action === 'add') { |
| | | dialogTitle.value = `新增${getTypeName(type)}` |
| | | currentEditId.value = '' |
| | | resetForm() |
| | | } else if (action === 'edit' && row) { |
| | | dialogTitle.value = `编辑${getTypeName(type)}` |
| | | currentEditId.value = row.id |
| | | fillForm(row) |
| | | } |
| | | |
| | | dialogVisible.value = true |
| | | } catch (error) { |
| | | console.error('打开弹窗失败:', error) |
| | | ElMessage.error('打开弹窗失败,请重试') |
| | | } |
| | | } |
| | | |
| | | const getTypeName = (type) => { |
| | | const nameMap = { |
| | | holiday: '假期', |
| | | annual: '年假规则', |
| | | overtime: '加班规则', |
| | | worktime: '时间段' |
| | | } |
| | | return nameMap[type] || '' |
| | | } |
| | | |
| | | const resetForm = () => { |
| | | Object.assign(form, { |
| | | name: '', |
| | | type: '', |
| | | // 表单数据 |
| | | const form = reactive({ |
| | | name: "", |
| | | type: "", |
| | | dateRange: [], |
| | | startDate: '', |
| | | endDate: '', |
| | | startDate: "", |
| | | endDate: "", |
| | | days: 0, |
| | | employeeType: '', |
| | | workYears: '', |
| | | employeeType: "", |
| | | workYears: "", |
| | | annualDays: 0, |
| | | maxCarryOver: 0, |
| | | startTime: '', |
| | | endTime: '', |
| | | workStartTime: '', |
| | | workEndTime: '', |
| | | startTime: "", // 加班开始时间 |
| | | endTime: "", // 加班结束时间 |
| | | workStartTime: "", // 上班时间 |
| | | workEndTime: "", // 下班时间 |
| | | rate: 1.5, |
| | | flexibleStart: false, |
| | | flexibleMinutes: 30, |
| | | status: 'active' |
| | | }) |
| | | } |
| | | status: "active", |
| | | }); |
| | | |
| | | const fillForm = (row) => { |
| | | if (currentType.value === 'holiday') { |
| | | Object.assign(form, { |
| | | name: row.name, |
| | | type: row.type, |
| | | dateRange: [new Date(row.startDate), new Date(row.endDate)], |
| | | startDate: row.startDate, |
| | | endDate: row.endDate, |
| | | days: row.days, |
| | | status: row.status |
| | | }) |
| | | } else if (currentType.value === 'annual') { |
| | | Object.assign(form, { |
| | | employeeType: row.employeeType, |
| | | workYears: row.workYears, |
| | | annualDays: row.annualDays, |
| | | maxCarryOver: row.maxCarryOver, |
| | | status: row.status |
| | | }) |
| | | } else if (currentType.value === 'overtime') { |
| | | Object.assign(form, { |
| | | name: row.name, |
| | | type: row.type, |
| | | startTime: row.startTime || '', |
| | | endTime: row.endTime || '', |
| | | rate: row.rate, |
| | | status: row.status |
| | | }) |
| | | } else if (currentType.value === 'worktime') { |
| | | Object.assign(form, { |
| | | name: row.name, |
| | | workStartTime: row.startTime || '', |
| | | workEndTime: row.endTime || '', |
| | | flexibleStart: row.flexibleStart, |
| | | flexibleMinutes: row.flexibleMinutes, |
| | | status: row.status |
| | | }) |
| | | } |
| | | } |
| | | // 表单验证规则 |
| | | const rules = { |
| | | name: [{ required: true, message: "请输入名称", trigger: "blur" }], |
| | | type: [{ required: true, message: "请选择类型", trigger: "change" }], |
| | | dateRange: [{ required: true, message: "请选择日期范围", trigger: "change" }], |
| | | days: [{ required: true, message: "请输入天数", trigger: "blur" }], |
| | | employeeType: [ |
| | | { required: true, message: "请选择员工类型", trigger: "change" }, |
| | | ], |
| | | workYears: [{ required: true, message: "请输入工作年限", trigger: "blur" }], |
| | | annualDays: [{ required: true, message: "请输入年假天数", trigger: "blur" }], |
| | | maxCarryOver: [ |
| | | { required: true, message: "请输入最大结转天数", trigger: "blur" }, |
| | | ], |
| | | startTime: [ |
| | | { |
| | | required: true, |
| | | message: "请选择开始时间", |
| | | trigger: "change", |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error("请选择开始时间")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | endTime: [ |
| | | { |
| | | required: true, |
| | | message: "请选择结束时间", |
| | | trigger: "change", |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error("请选择结束时间")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | workStartTime: [ |
| | | { |
| | | required: true, |
| | | message: "请选择上班时间", |
| | | trigger: "change", |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error("请选择上班时间")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | workEndTime: [ |
| | | { |
| | | required: true, |
| | | message: "请选择下班时间", |
| | | trigger: "change", |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error("请选择下班时间")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | rate: [{ required: true, message: "请输入倍率", trigger: "blur" }], |
| | | }; |
| | | // 工具函数 |
| | | const getTagType = type => { |
| | | const tagMap = { |
| | | legal: "success", |
| | | adjustment: "warning", |
| | | special: "info", |
| | | company: "primary", |
| | | weekday: "primary", |
| | | weekend: "warning", |
| | | holiday: "danger", |
| | | night: "info", |
| | | regular: "success", |
| | | probation: "info", |
| | | intern: "danger", |
| | | }; |
| | | return tagMap[type] || "info"; |
| | | }; |
| | | |
| | | // 提交表单 |
| | | const submitForm = async () => { |
| | | try { |
| | | if (!formRef.value) { |
| | | ElMessage.error('表单引用不存在') |
| | | return |
| | | const getTypeLabel = type => { |
| | | const labelMap = { |
| | | legal: "法定节假日", |
| | | adjustment: "调休日", |
| | | special: "特殊假期", |
| | | company: "公司假期", |
| | | weekday: "工作日加班", |
| | | weekend: "周末加班", |
| | | holiday: "节假日加班", |
| | | night: "深夜加班", |
| | | regular: "正式员工", |
| | | probation: "试用期员工", |
| | | intern: "实习生", |
| | | }; |
| | | return labelMap[type] || type; |
| | | }; |
| | | |
| | | // 打卡记录相关工具函数 |
| | | const getAttendanceTagType = status => { |
| | | const tagMap = { |
| | | normal: "success", |
| | | late: "warning", |
| | | early: "warning", |
| | | absent: "danger", |
| | | }; |
| | | return tagMap[status] || "info"; |
| | | }; |
| | | |
| | | const getAttendanceStatusLabel = status => { |
| | | const labelMap = { |
| | | normal: "正常", |
| | | late: "迟到", |
| | | early: "早退", |
| | | absent: "缺勤", |
| | | }; |
| | | return labelMap[status] || status; |
| | | }; |
| | | |
| | | const getTypeOptions = () => { |
| | | if (currentType.value === "holiday") { |
| | | return [ |
| | | { label: "法定节假日", value: "legal" }, |
| | | { label: "调休日", value: "adjustment" }, |
| | | { label: "特殊假期", value: "special" }, |
| | | { label: "公司假期", value: "company" }, |
| | | ]; |
| | | } else if (currentType.value === "overtime") { |
| | | return [ |
| | | { label: "工作日加班", value: "weekday" }, |
| | | { label: "周末加班", value: "weekend" }, |
| | | { label: "节假日加班", value: "holiday" }, |
| | | { label: "深夜加班", value: "night" }, |
| | | ]; |
| | | } else if (currentType.value === "annual") { |
| | | return [ |
| | | { label: "正式员工", value: "regular" }, |
| | | { label: "试用期员工", value: "probation" }, |
| | | { label: "实习生", value: "intern" }, |
| | | ]; |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | await formRef.value.validate() |
| | | // 计算假期天数 |
| | | const calculateDays = () => { |
| | | try { |
| | | if ( |
| | | form.dateRange && |
| | | form.dateRange.length === 2 && |
| | | form.dateRange[0] && |
| | | form.dateRange[1] |
| | | ) { |
| | | const start = new Date(form.dateRange[0]); |
| | | const end = new Date(form.dateRange[1]); |
| | | form.startDate = start.toISOString().split("T")[0]; |
| | | form.endDate = end.toISOString().split("T")[0]; |
| | | |
| | | if (currentAction.value === 'add') { |
| | | addItem() |
| | | } else if (currentAction.value === 'edit') { |
| | | editItem() |
| | | } |
| | | |
| | | dialogVisible.value = false |
| | | ElMessage.success('操作成功') |
| | | } catch (error) { |
| | | console.error('表单验证失败:', error) |
| | | ElMessage.error('表单验证失败,请检查输入') |
| | | } |
| | | } |
| | | |
| | | const addItem = () => { |
| | | |
| | | if (currentType.value === 'holiday') { |
| | | const params = { |
| | | name: form.name, |
| | | type: form.type, |
| | | startDate: form.startDate, |
| | | endDate: form.endDate, |
| | | days: form.days, |
| | | status: form.status |
| | | } |
| | | addHolidaySettings(params).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("添加成功"); |
| | | // dialogVisible.value = false; |
| | | getHolidaySettingsList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | } else if (currentType.value === 'annual') { |
| | | // annualData.value.push(newItem) |
| | | const params = { |
| | | employeeType: form.employeeType, |
| | | workYears: form.workYears, |
| | | annualDays: form.annualDays, |
| | | maxCarryOver: form.maxCarryOver, |
| | | status: form.status |
| | | } |
| | | addAnnualLeaveSetting(params).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("添加成功"); |
| | | // dialogVisible.value = false; |
| | | getAnnualLeaveSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | } else if (currentType.value === 'overtime') { |
| | | const params = { |
| | | name: form.name, |
| | | type: form.type, |
| | | startTime: form.startTime || '', |
| | | endTime: form.endTime || '', |
| | | rate: form.rate, |
| | | status: form.status |
| | | } |
| | | addOvertimeSetting(params).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("添加成功"); |
| | | // dialogVisible.value = false; |
| | | getOvertimeSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | // newItem.startTime = form.startTime || '' |
| | | // newItem.endTime = form.endTime || '' |
| | | // overtimeData.value.push(newItem) |
| | | } else if (currentType.value === 'worktime') { |
| | | const params = { |
| | | name: form.name, |
| | | startTime: form.workStartTime || '', |
| | | endTime: form.workEndTime || '', |
| | | flexibleStart: form.flexibleStart, |
| | | flexibleMinutes: form.flexibleMinutes, |
| | | status: form.status |
| | | } |
| | | addWorkingHoursSetting(params).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("添加成功"); |
| | | getWorkingHoursSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | // newItem.startTime = form.workStartTime || '' |
| | | // newItem.endTime = form.workEndTime || '' |
| | | // worktimeData.value.push(newItem) |
| | | } |
| | | } |
| | | |
| | | const editItem = () => { |
| | | let dataArray |
| | | let index |
| | | |
| | | if (currentType.value === 'holiday') { |
| | | const params = { |
| | | id: currentEditId.value, |
| | | name: form.name, |
| | | type: form.type, |
| | | startDate: form.dateRange[0].toISOString().split('T')[0], |
| | | endDate: form.dateRange[1].toISOString().split('T')[0], |
| | | days: form.days, |
| | | status: form.status |
| | | } |
| | | updateHolidaySettings(params).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("更新成功"); |
| | | // dialogVisible.value = false; |
| | | getHolidaySettingsList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | } else if (currentType.value === 'annual') { |
| | | const params = { |
| | | id: currentEditId.value, |
| | | employeeType: form.employeeType, |
| | | workYears: form.workYears, |
| | | annualDays: form.annualDays, |
| | | maxCarryOver: form.maxCarryOver, |
| | | status: form.status |
| | | } |
| | | updateAnnualLeaveSetting(params).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("更新成功"); |
| | | getAnnualLeaveSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | } else if (currentType.value === 'overtime') { |
| | | const params = { |
| | | id: currentEditId.value, |
| | | name: form.name, |
| | | type: form.type, |
| | | startTime: form.startTime || '', |
| | | endTime: form.endTime || '', |
| | | rate: form.rate, |
| | | status: form.status |
| | | } |
| | | updateOvertimeSetting(params).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("更新成功"); |
| | | getOvertimeSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | |
| | | // dataArray = overtimeData.value |
| | | // index = dataArray.findIndex(item => item.id === currentEditId.value) |
| | | // if (index > -1) { |
| | | // dataArray[index] = { |
| | | // ...dataArray[index], |
| | | // name: form.name, |
| | | // type: form.type, |
| | | // startTime: form.startTime || '', |
| | | // endTime: form.endTime || '', |
| | | // rate: form.rate, |
| | | // status: form.status |
| | | // } |
| | | // } |
| | | } else if (currentType.value === 'worktime') { |
| | | const params = { |
| | | id: currentEditId.value, |
| | | name: form.name, |
| | | startTime: form.workStartTime || '', |
| | | endTime: form.workEndTime || '', |
| | | flexibleStart: form.flexibleStart, |
| | | flexibleMinutes: form.flexibleMinutes, |
| | | status: form.status |
| | | } |
| | | updateWorkingHoursSetting(params).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("更新成功"); |
| | | getWorkingHoursSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | // dataArray = worktimeData.value |
| | | // index = dataArray.findIndex(item => item.id === currentEditId.value) |
| | | // if (index > -1) { |
| | | // dataArray[index] = { |
| | | // ...dataArray[index], |
| | | // name: form.name, |
| | | // startTime: form.workStartTime || '', |
| | | // endTime: form.workEndTime || '', |
| | | // flexibleStart: form.flexibleStart, |
| | | // flexibleMinutes: form.flexibleMinutes, |
| | | // status: form.status |
| | | // } |
| | | // } |
| | | } |
| | | } |
| | | |
| | | // 打卡记录过滤功能 |
| | | const filterAttendanceData = () => { |
| | | let filtered = attendanceData.value |
| | | |
| | | // 按日期过滤 |
| | | if (attendanceDate.value) { |
| | | filtered = filtered.filter(item => item.date === attendanceDate.value) |
| | | } |
| | | |
| | | // 按状态过滤 |
| | | if (attendanceStatus.value) { |
| | | filtered = filtered.filter(item => item.status === attendanceStatus.value) |
| | | } |
| | | |
| | | filteredAttendanceData.value = filtered |
| | | } |
| | | |
| | | // 导出打卡记录 |
| | | const exportAttendance = () => { |
| | | ElMessage.success('导出功能开发中...') |
| | | } |
| | | |
| | | // 初始化打卡记录假数据 |
| | | const initAttendanceData = () => { |
| | | const mockData = [ |
| | | { |
| | | id: 1, |
| | | employeeName: '陈志强', |
| | | department: '技术部', |
| | | date: '2025-08-15', |
| | | clockInTime: '09:00:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '8.0h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 2, |
| | | employeeName: '李雪梅', |
| | | department: '市场部', |
| | | date: '2025-08-16', |
| | | clockInTime: '08:58:00', |
| | | clockOutTime: '18:05:00', |
| | | workHours: '8.12h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 3, |
| | | employeeName: '王建华', |
| | | department: '人事部', |
| | | date: '2025-08-16', |
| | | clockInTime: '09:02:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '7.97h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 4, |
| | | employeeName: '赵晓丽', |
| | | department: '财务部', |
| | | date: '2025-09-02', |
| | | clockInTime: '08:55:00', |
| | | clockOutTime: '18:10:00', |
| | | workHours: '8.25h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 5, |
| | | employeeName: '张国庆', |
| | | department: '技术部', |
| | | date: '2025-09-02', |
| | | clockInTime: '09:00:00', |
| | | clockOutTime: '18:30:00', |
| | | workHours: '8.5h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '加班' |
| | | }, |
| | | { |
| | | id: 6, |
| | | employeeName: '刘明辉', |
| | | department: '运营部', |
| | | date: '2025-09-03', |
| | | clockInTime: '09:05:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '7.92h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 7, |
| | | employeeName: '孙丽华', |
| | | department: '设计部', |
| | | date: '2025-09-03', |
| | | clockInTime: '08:59:00', |
| | | clockOutTime: '18:02:00', |
| | | workHours: '8.05h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 8, |
| | | employeeName: '周建军', |
| | | department: '销售部', |
| | | date: '2025-09-04', |
| | | clockInTime: '09:15:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '7.75h', |
| | | status: 'late', |
| | | location: '公司总部', |
| | | remark: '交通堵塞' |
| | | }, |
| | | { |
| | | id: 9, |
| | | employeeName: '吴小芳', |
| | | department: '客服部', |
| | | date: '2025-09-04', |
| | | clockInTime: '09:01:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '7.98h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 10, |
| | | employeeName: '马文杰', |
| | | department: '技术部', |
| | | date: '2025-09-05', |
| | | clockInTime: '08:57:00', |
| | | clockOutTime: '17:30:00', |
| | | workHours: '7.55h', |
| | | status: 'early', |
| | | location: '公司总部', |
| | | remark: '有急事提前离开' |
| | | }, |
| | | { |
| | | id: 11, |
| | | employeeName: '林晓东', |
| | | department: '行政部', |
| | | date: '2025-09-05', |
| | | clockInTime: '09:03:00', |
| | | clockOutTime: '18:08:00', |
| | | workHours: '8.08h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 12, |
| | | employeeName: '黄美玲', |
| | | department: '财务部', |
| | | date: '2025-09-06', |
| | | clockInTime: '', |
| | | clockOutTime: '', |
| | | workHours: '0h', |
| | | status: 'absent', |
| | | location: '', |
| | | remark: '请病假' |
| | | }, |
| | | { |
| | | id: 13, |
| | | employeeName: '郑海涛', |
| | | department: '市场部', |
| | | date: '2025-08-14', |
| | | clockInTime: '09:00:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '8.0h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 14, |
| | | employeeName: '谢丽娟', |
| | | department: '人事部', |
| | | date: '2025-08-20', |
| | | clockInTime: '08:58:00', |
| | | clockOutTime: '18:03:00', |
| | | workHours: '8.08h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 15, |
| | | employeeName: '何志伟', |
| | | department: '技术部', |
| | | date: '2025-08-21', |
| | | clockInTime: '09:10:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '7.83h', |
| | | status: 'late', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 16, |
| | | employeeName: '许雅芳', |
| | | department: '设计部', |
| | | date: '2025-08-22', |
| | | clockInTime: '09:01:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '7.98h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 17, |
| | | employeeName: '邓建平', |
| | | department: '运营部', |
| | | date: '2025-09-10', |
| | | clockInTime: '08:59:00', |
| | | clockOutTime: '18:05:00', |
| | | workHours: '8.1h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | }, |
| | | { |
| | | id: 18, |
| | | employeeName: '曾小红', |
| | | department: '客服部', |
| | | date: '2025-09-11', |
| | | clockInTime: '09:02:00', |
| | | clockOutTime: '18:00:00', |
| | | workHours: '7.97h', |
| | | status: 'normal', |
| | | location: '公司总部', |
| | | remark: '' |
| | | } |
| | | ] |
| | | |
| | | attendanceData.value = mockData |
| | | filteredAttendanceData.value = mockData |
| | | } |
| | | |
| | | // 删除项目 |
| | | const deleteItem = (type, row) => { |
| | | ElMessageBox.confirm('确定要删除这个项目吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | let ids = []; |
| | | let dataArray |
| | | if (type === 'holiday') { |
| | | ids.push(row.id) |
| | | delHolidaySettings(ids).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("删除成功"); |
| | | ids = [] |
| | | getHolidaySettingsList() |
| | | if (isNaN(start.getTime()) || isNaN(end.getTime())) { |
| | | console.warn("无效的日期格式"); |
| | | return; |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | |
| | | const diffTime = Math.abs(end - start); |
| | | const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1; |
| | | form.days = diffDays; |
| | | } |
| | | } catch (error) { |
| | | console.error("计算天数失败:", error); |
| | | } |
| | | else if (type === 'annual') { |
| | | ids.push(row.id) |
| | | delAnnualLeaveSetting(ids).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("删除成功"); |
| | | ids = [] |
| | | getAnnualLeaveSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | }; |
| | | |
| | | // 验证时间格式 |
| | | // const validateTime = (time) => { |
| | | // if (!time) return '' |
| | | // if (typeof time === 'string') return time |
| | | // if (time instanceof Date) { |
| | | // return time.toTimeString().slice(0, 5) |
| | | // } |
| | | // return '' |
| | | // } |
| | | |
| | | // 验证时间字段 |
| | | const validateTimeField = fieldName => { |
| | | try { |
| | | const value = form[fieldName]; |
| | | if (value && typeof value === "object" && value.hour !== undefined) { |
| | | // 如果是时间对象,转换为字符串格式 |
| | | const hours = value.hour.toString().padStart(2, "0"); |
| | | const minutes = value.minute.toString().padStart(2, "0"); |
| | | form[fieldName] = `${hours}:${minutes}`; |
| | | } |
| | | } catch (error) { |
| | | console.error(`验证时间字段 ${fieldName} 失败:`, error); |
| | | form[fieldName] = ""; |
| | | } |
| | | else if (type === 'overtime') { |
| | | ids.push(row.id) |
| | | delOvertimeSetting(ids).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("删除成功"); |
| | | ids = [] |
| | | getOvertimeSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | }; |
| | | |
| | | // 打开弹窗 |
| | | const openDialog = (type, action, row = null) => { |
| | | try { |
| | | currentType.value = type; |
| | | currentAction.value = action; |
| | | |
| | | if (action === "add") { |
| | | dialogTitle.value = `新增${getTypeName(type)}`; |
| | | currentEditId.value = ""; |
| | | resetForm(); |
| | | } else if (action === "edit" && row) { |
| | | dialogTitle.value = `编辑${getTypeName(type)}`; |
| | | currentEditId.value = row.id; |
| | | fillForm(row); |
| | | } |
| | | |
| | | dialogVisible.value = true; |
| | | } catch (error) { |
| | | console.error("打开弹窗失败:", error); |
| | | ElMessage.error("打开弹窗失败,请重试"); |
| | | } |
| | | else if (type === 'worktime') { |
| | | ids.push(row.id) |
| | | delWorkingHoursSetting(ids).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("删除成功"); |
| | | ids = [] |
| | | getWorkingHoursSettingList() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | }; |
| | | |
| | | const getTypeName = type => { |
| | | const nameMap = { |
| | | holiday: "假期", |
| | | annual: "年假规则", |
| | | overtime: "加班规则", |
| | | worktime: "时间段", |
| | | }; |
| | | return nameMap[type] || ""; |
| | | }; |
| | | |
| | | const resetForm = () => { |
| | | Object.assign(form, { |
| | | name: "", |
| | | type: "", |
| | | dateRange: [], |
| | | startDate: "", |
| | | endDate: "", |
| | | days: 0, |
| | | employeeType: "", |
| | | workYears: "", |
| | | annualDays: 0, |
| | | maxCarryOver: 0, |
| | | startTime: "", |
| | | endTime: "", |
| | | workStartTime: "", |
| | | workEndTime: "", |
| | | rate: 1.5, |
| | | flexibleStart: false, |
| | | flexibleMinutes: 30, |
| | | status: "active", |
| | | }); |
| | | }; |
| | | |
| | | const fillForm = row => { |
| | | if (currentType.value === "holiday") { |
| | | Object.assign(form, { |
| | | name: row.name, |
| | | type: row.type, |
| | | dateRange: [new Date(row.startDate), new Date(row.endDate)], |
| | | startDate: row.startDate, |
| | | endDate: row.endDate, |
| | | days: row.days, |
| | | status: row.status, |
| | | }); |
| | | } else if (currentType.value === "annual") { |
| | | Object.assign(form, { |
| | | employeeType: row.employeeType, |
| | | workYears: row.workYears, |
| | | annualDays: row.annualDays, |
| | | maxCarryOver: row.maxCarryOver, |
| | | status: row.status, |
| | | }); |
| | | } else if (currentType.value === "overtime") { |
| | | Object.assign(form, { |
| | | name: row.name, |
| | | type: row.type, |
| | | startTime: row.startTime || "", |
| | | endTime: row.endTime || "", |
| | | rate: row.rate, |
| | | status: row.status, |
| | | }); |
| | | } else if (currentType.value === "worktime") { |
| | | Object.assign(form, { |
| | | name: row.name, |
| | | workStartTime: row.startTime || "", |
| | | workEndTime: row.endTime || "", |
| | | flexibleStart: row.flexibleStart, |
| | | flexibleMinutes: row.flexibleMinutes, |
| | | status: row.status, |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | // 提交表单 |
| | | const submitForm = async () => { |
| | | try { |
| | | if (!formRef.value) { |
| | | ElMessage.error("表单引用不存在"); |
| | | return; |
| | | } |
| | | |
| | | await formRef.value.validate(); |
| | | |
| | | if (currentAction.value === "add") { |
| | | addItem(); |
| | | } else if (currentAction.value === "edit") { |
| | | editItem(); |
| | | } |
| | | |
| | | dialogVisible.value = false; |
| | | ElMessage.success("操作成功"); |
| | | } catch (error) { |
| | | console.error("表单验证失败:", error); |
| | | ElMessage.error("表单验证失败,请检查输入"); |
| | | } |
| | | }; |
| | | |
| | | const addItem = () => { |
| | | if (currentType.value === "holiday") { |
| | | const params = { |
| | | name: form.name, |
| | | type: form.type, |
| | | startDate: form.startDate, |
| | | endDate: form.endDate, |
| | | days: form.days, |
| | | status: form.status, |
| | | }; |
| | | addHolidaySettings(params) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("添加成功"); |
| | | // dialogVisible.value = false; |
| | | getHolidaySettingsList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else if (currentType.value === "annual") { |
| | | // annualData.value.push(newItem) |
| | | const params = { |
| | | employeeType: form.employeeType, |
| | | workYears: form.workYears, |
| | | annualDays: form.annualDays, |
| | | maxCarryOver: form.maxCarryOver, |
| | | status: form.status, |
| | | }; |
| | | addAnnualLeaveSetting(params) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("添加成功"); |
| | | // dialogVisible.value = false; |
| | | getAnnualLeaveSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else if (currentType.value === "overtime") { |
| | | const params = { |
| | | name: form.name, |
| | | type: form.type, |
| | | startTime: form.startTime || "", |
| | | endTime: form.endTime || "", |
| | | rate: form.rate, |
| | | status: form.status, |
| | | }; |
| | | addOvertimeSetting(params) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("添加成功"); |
| | | // dialogVisible.value = false; |
| | | getOvertimeSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | // newItem.startTime = form.startTime || '' |
| | | // newItem.endTime = form.endTime || '' |
| | | // overtimeData.value.push(newItem) |
| | | } else if (currentType.value === "worktime") { |
| | | const params = { |
| | | name: form.name, |
| | | startTime: form.workStartTime || "", |
| | | endTime: form.workEndTime || "", |
| | | flexibleStart: form.flexibleStart, |
| | | flexibleMinutes: form.flexibleMinutes, |
| | | status: form.status, |
| | | }; |
| | | addWorkingHoursSetting(params) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("添加成功"); |
| | | getWorkingHoursSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | // newItem.startTime = form.workStartTime || '' |
| | | // newItem.endTime = form.workEndTime || '' |
| | | // worktimeData.value.push(newItem) |
| | | } |
| | | }; |
| | | |
| | | const editItem = () => { |
| | | let dataArray; |
| | | let index; |
| | | |
| | | if (currentType.value === "holiday") { |
| | | const params = { |
| | | id: currentEditId.value, |
| | | name: form.name, |
| | | type: form.type, |
| | | startDate: form.dateRange[0].toISOString().split("T")[0], |
| | | endDate: form.dateRange[1].toISOString().split("T")[0], |
| | | days: form.days, |
| | | status: form.status, |
| | | }; |
| | | updateHolidaySettings(params) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("更新成功"); |
| | | // dialogVisible.value = false; |
| | | getHolidaySettingsList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else if (currentType.value === "annual") { |
| | | const params = { |
| | | id: currentEditId.value, |
| | | employeeType: form.employeeType, |
| | | workYears: form.workYears, |
| | | annualDays: form.annualDays, |
| | | maxCarryOver: form.maxCarryOver, |
| | | status: form.status, |
| | | }; |
| | | updateAnnualLeaveSetting(params) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("更新成功"); |
| | | getAnnualLeaveSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else if (currentType.value === "overtime") { |
| | | const params = { |
| | | id: currentEditId.value, |
| | | name: form.name, |
| | | type: form.type, |
| | | startTime: form.startTime || "", |
| | | endTime: form.endTime || "", |
| | | rate: form.rate, |
| | | status: form.status, |
| | | }; |
| | | updateOvertimeSetting(params) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("更新成功"); |
| | | getOvertimeSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | |
| | | // dataArray = overtimeData.value |
| | | // index = dataArray.findIndex(item => item.id === currentEditId.value) |
| | | // if (index > -1) { |
| | | // dataArray[index] = { |
| | | // ...dataArray[index], |
| | | // name: form.name, |
| | | // type: form.type, |
| | | // startTime: form.startTime || '', |
| | | // endTime: form.endTime || '', |
| | | // rate: form.rate, |
| | | // status: form.status |
| | | // } |
| | | // } |
| | | } else if (currentType.value === "worktime") { |
| | | const params = { |
| | | id: currentEditId.value, |
| | | name: form.name, |
| | | startTime: form.workStartTime || "", |
| | | endTime: form.workEndTime || "", |
| | | flexibleStart: form.flexibleStart, |
| | | flexibleMinutes: form.flexibleMinutes, |
| | | status: form.status, |
| | | }; |
| | | updateWorkingHoursSetting(params) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("更新成功"); |
| | | getWorkingHoursSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | // dataArray = worktimeData.value |
| | | // index = dataArray.findIndex(item => item.id === currentEditId.value) |
| | | // if (index > -1) { |
| | | // dataArray[index] = { |
| | | // ...dataArray[index], |
| | | // name: form.name, |
| | | // startTime: form.workStartTime || '', |
| | | // endTime: form.workEndTime || '', |
| | | // flexibleStart: form.flexibleStart, |
| | | // flexibleMinutes: form.flexibleMinutes, |
| | | // status: form.status |
| | | // } |
| | | // } |
| | | } |
| | | }; |
| | | |
| | | // 打卡记录过滤功能 |
| | | const filterAttendanceData = () => { |
| | | let filtered = attendanceData.value; |
| | | |
| | | // 按日期过滤 |
| | | if (attendanceDate.value) { |
| | | filtered = filtered.filter(item => item.date === attendanceDate.value); |
| | | } |
| | | |
| | | // const index = dataArray.findIndex(item => item.id === row.id) |
| | | // if (index > -1) { |
| | | // dataArray.splice(index, 1) |
| | | // ElMessage.success('删除成功') |
| | | // } |
| | | }) |
| | | } |
| | | // 获取假期设置列表 |
| | | const getHolidaySettingsList = () => { |
| | | // tableLoading.value = true; |
| | | listHolidaySettings({...page.value}) |
| | | .then(res => { |
| | | // tableLoading.value = false; |
| | | holidayData.value = res.data.records |
| | | page.total = res.data.total; |
| | | }).catch(err => { |
| | | // tableLoading.value = false; |
| | | }) |
| | | }; |
| | | // 获取年假规则列表 |
| | | const getAnnualLeaveSettingList = () => { |
| | | // 按状态过滤 |
| | | if (attendanceStatus.value) { |
| | | filtered = filtered.filter(item => item.status === attendanceStatus.value); |
| | | } |
| | | |
| | | listAnnualLeaveSettingList({...page.value}) |
| | | .then(res => { |
| | | // console.log(res.data) |
| | | annualData.value = res.data.records |
| | | page.total = res.data.total; |
| | | }).catch(err => { |
| | | }) |
| | | }; |
| | | // 获取加班规则列表 |
| | | const getOvertimeSettingList = () => { |
| | | filteredAttendanceData.value = filtered; |
| | | }; |
| | | |
| | | listOvertimeSettingList({...page.value}) |
| | | .then(res => { |
| | | // console.log(res.data) |
| | | overtimeData.value = res.data.records |
| | | page.total = res.data.total; |
| | | }).catch(err => { |
| | | }) |
| | | }; |
| | | // 获取工作时间规则列表 |
| | | const getWorkingHoursSettingList = () => { |
| | | // 导出打卡记录 |
| | | const exportAttendance = () => { |
| | | ElMessage.success("导出功能开发中..."); |
| | | }; |
| | | |
| | | listWorkingHoursSettingList({...page.value}) |
| | | .then(res => { |
| | | // console.log(res.data) |
| | | worktimeData.value = res.data.records |
| | | page.total = res.data.total; |
| | | }).catch(err => { |
| | | }) |
| | | }; |
| | | onMounted(() => { |
| | | getHolidaySettingsList() |
| | | getAnnualLeaveSettingList() |
| | | getOvertimeSettingList() |
| | | getWorkingHoursSettingList() |
| | | initAttendanceData() |
| | | console.log('考勤管理页面加载完成') |
| | | }) |
| | | // 初始化打卡记录假数据 |
| | | const initAttendanceData = () => { |
| | | const mockData = [ |
| | | { |
| | | id: 1, |
| | | employeeName: "陈志强", |
| | | department: "技术部", |
| | | date: "2025-08-15", |
| | | clockInTime: "09:00:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "8.0h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 2, |
| | | employeeName: "李雪梅", |
| | | department: "市场部", |
| | | date: "2025-08-16", |
| | | clockInTime: "08:58:00", |
| | | clockOutTime: "18:05:00", |
| | | workHours: "8.12h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 3, |
| | | employeeName: "王建华", |
| | | department: "人事部", |
| | | date: "2025-08-16", |
| | | clockInTime: "09:02:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "7.97h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 4, |
| | | employeeName: "赵晓丽", |
| | | department: "财务部", |
| | | date: "2025-09-02", |
| | | clockInTime: "08:55:00", |
| | | clockOutTime: "18:10:00", |
| | | workHours: "8.25h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 5, |
| | | employeeName: "张国庆", |
| | | department: "技术部", |
| | | date: "2025-09-02", |
| | | clockInTime: "09:00:00", |
| | | clockOutTime: "18:30:00", |
| | | workHours: "8.5h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "加班", |
| | | }, |
| | | { |
| | | id: 6, |
| | | employeeName: "刘明辉", |
| | | department: "运营部", |
| | | date: "2025-09-03", |
| | | clockInTime: "09:05:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "7.92h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 7, |
| | | employeeName: "孙丽华", |
| | | department: "设计部", |
| | | date: "2025-09-03", |
| | | clockInTime: "08:59:00", |
| | | clockOutTime: "18:02:00", |
| | | workHours: "8.05h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 8, |
| | | employeeName: "周建军", |
| | | department: "销售部", |
| | | date: "2025-09-04", |
| | | clockInTime: "09:15:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "7.75h", |
| | | status: "late", |
| | | location: "公司总部", |
| | | remark: "交通堵塞", |
| | | }, |
| | | { |
| | | id: 9, |
| | | employeeName: "吴小芳", |
| | | department: "客服部", |
| | | date: "2025-09-04", |
| | | clockInTime: "09:01:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "7.98h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 10, |
| | | employeeName: "马文杰", |
| | | department: "技术部", |
| | | date: "2025-09-05", |
| | | clockInTime: "08:57:00", |
| | | clockOutTime: "17:30:00", |
| | | workHours: "7.55h", |
| | | status: "early", |
| | | location: "公司总部", |
| | | remark: "有急事提前离开", |
| | | }, |
| | | { |
| | | id: 11, |
| | | employeeName: "林晓东", |
| | | department: "行政部", |
| | | date: "2025-09-05", |
| | | clockInTime: "09:03:00", |
| | | clockOutTime: "18:08:00", |
| | | workHours: "8.08h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 12, |
| | | employeeName: "黄美玲", |
| | | department: "财务部", |
| | | date: "2025-09-06", |
| | | clockInTime: "", |
| | | clockOutTime: "", |
| | | workHours: "0h", |
| | | status: "absent", |
| | | location: "", |
| | | remark: "请病假", |
| | | }, |
| | | { |
| | | id: 13, |
| | | employeeName: "郑海涛", |
| | | department: "市场部", |
| | | date: "2025-08-14", |
| | | clockInTime: "09:00:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "8.0h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 14, |
| | | employeeName: "谢丽娟", |
| | | department: "人事部", |
| | | date: "2025-08-20", |
| | | clockInTime: "08:58:00", |
| | | clockOutTime: "18:03:00", |
| | | workHours: "8.08h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 15, |
| | | employeeName: "何志伟", |
| | | department: "技术部", |
| | | date: "2025-08-21", |
| | | clockInTime: "09:10:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "7.83h", |
| | | status: "late", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 16, |
| | | employeeName: "许雅芳", |
| | | department: "设计部", |
| | | date: "2025-08-22", |
| | | clockInTime: "09:01:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "7.98h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 17, |
| | | employeeName: "邓建平", |
| | | department: "运营部", |
| | | date: "2025-09-10", |
| | | clockInTime: "08:59:00", |
| | | clockOutTime: "18:05:00", |
| | | workHours: "8.1h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 18, |
| | | employeeName: "曾小红", |
| | | department: "客服部", |
| | | date: "2025-09-11", |
| | | clockInTime: "09:02:00", |
| | | clockOutTime: "18:00:00", |
| | | workHours: "7.97h", |
| | | status: "normal", |
| | | location: "公司总部", |
| | | remark: "", |
| | | }, |
| | | ]; |
| | | |
| | | onUnmounted(() => { |
| | | // 清理工作 |
| | | dialogVisible.value = false |
| | | currentType.value = '' |
| | | currentAction.value = '' |
| | | currentEditId.value = '' |
| | | }) |
| | | attendanceData.value = mockData; |
| | | filteredAttendanceData.value = mockData; |
| | | }; |
| | | |
| | | // 删除项目 |
| | | const deleteItem = (type, row) => { |
| | | ElMessageBox.confirm("确定要删除这个项目吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | let ids = []; |
| | | let dataArray; |
| | | if (type === "holiday") { |
| | | ids.push(row.id); |
| | | delHolidaySettings(ids) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("删除成功"); |
| | | ids = []; |
| | | getHolidaySettingsList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else if (type === "annual") { |
| | | ids.push(row.id); |
| | | delAnnualLeaveSetting(ids) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("删除成功"); |
| | | ids = []; |
| | | getAnnualLeaveSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else if (type === "overtime") { |
| | | ids.push(row.id); |
| | | delOvertimeSetting(ids) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("删除成功"); |
| | | ids = []; |
| | | getOvertimeSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else if (type === "worktime") { |
| | | ids.push(row.id); |
| | | delWorkingHoursSetting(ids) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("删除成功"); |
| | | ids = []; |
| | | getWorkingHoursSettingList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } |
| | | |
| | | // const index = dataArray.findIndex(item => item.id === row.id) |
| | | // if (index > -1) { |
| | | // dataArray.splice(index, 1) |
| | | // ElMessage.success('删除成功') |
| | | // } |
| | | }); |
| | | }; |
| | | // 获取假期设置列表 |
| | | const getHolidaySettingsList = () => { |
| | | // tableLoading.value = true; |
| | | listHolidaySettings({ ...page.value }) |
| | | .then(res => { |
| | | // tableLoading.value = false; |
| | | holidayData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }) |
| | | .catch(err => { |
| | | // tableLoading.value = false; |
| | | }); |
| | | }; |
| | | // 获取年假规则列表 |
| | | const getAnnualLeaveSettingList = () => { |
| | | listAnnualLeaveSettingList({ ...page.value }) |
| | | .then(res => { |
| | | // console.log(res.data) |
| | | annualData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }) |
| | | .catch(err => {}); |
| | | }; |
| | | // 获取加班规则列表 |
| | | const getOvertimeSettingList = () => { |
| | | listOvertimeSettingList({ ...page.value }) |
| | | .then(res => { |
| | | // console.log(res.data) |
| | | overtimeData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }) |
| | | .catch(err => {}); |
| | | }; |
| | | // 获取工作时间规则列表 |
| | | const getWorkingHoursSettingList = () => { |
| | | listWorkingHoursSettingList({ ...page.value }) |
| | | .then(res => { |
| | | // console.log(res.data) |
| | | worktimeData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }) |
| | | .catch(err => {}); |
| | | }; |
| | | onMounted(() => { |
| | | getHolidaySettingsList(); |
| | | getAnnualLeaveSettingList(); |
| | | getOvertimeSettingList(); |
| | | getWorkingHoursSettingList(); |
| | | initAttendanceData(); |
| | | console.log("考勤管理页面加载完成"); |
| | | }); |
| | | |
| | | onUnmounted(() => { |
| | | // 清理工作 |
| | | dialogVisible.value = false; |
| | | currentType.value = ""; |
| | | currentAction.value = ""; |
| | | currentEditId.value = ""; |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .tab-content { |
| | | padding: 20px 0; |
| | | } |
| | | .tab-content { |
| | | padding: 20px 0; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | |
| | | :deep(.el-tabs__content) { |
| | | padding: 20px; |
| | | } |
| | | :deep(.el-tabs__content) { |
| | | padding: 20px; |
| | | } |
| | | |
| | | :deep(.el-form-item) { |
| | | margin-bottom: 20px; |
| | | } |
| | | :deep(.el-form-item) { |
| | | margin-bottom: 20px; |
| | | } |
| | | </style> |