gaoluyang
10 小时以前 1f55a1dc8273985685b79604dc9d60b908319934
src/views/collaborativeApproval/attendanceManagement/index.vue
@@ -5,7 +5,7 @@
      <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="假期类型">
@@ -37,7 +37,7 @@
      <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="员工类型">
              <template #default="scope">
@@ -68,7 +68,7 @@
      <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="加班类型" >
@@ -100,7 +100,7 @@
      <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="上班时间"/>
@@ -129,6 +129,52 @@
          </el-table>
        </div>
      </el-tab-pane>
      <!-- 打卡记录 -->
      <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-select>
            <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">
              <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>
        </div>
      </el-tab-pane>
    </el-tabs>
    <!-- 通用弹窗 -->
@@ -137,14 +183,14 @@
        <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-option
              v-for="option in getTypeOptions()"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
        </el-form-item>
@@ -154,11 +200,11 @@
            <!-- <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>
@@ -201,7 +247,7 @@
             @change="validateTimeField('startTime')"
           />
         </el-form-item>
         <el-form-item label="结束时间" prop="endTime" v-if="currentType === 'overtime'">
           <el-time-picker
             v-model="form.endTime"
@@ -254,7 +300,7 @@
           </el-radio-group>
         </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
@@ -290,6 +336,12 @@
const overtimeData = ref([])
const worktimeData = ref([])
// 打卡记录相关数据
const attendanceData = ref([])
const filteredAttendanceData = ref([])
const attendanceDate = ref('')
const attendanceStatus = ref('')
// 表单数据
const form = reactive({
  name: '',
@@ -322,9 +374,9 @@
  workYears: [{ required: true, message: '请输入工作年限', trigger: 'blur' }],
  annualDays: [{ required: true, message: '请输入年假天数', trigger: 'blur' }],
  maxCarryOver: [{ required: true, message: '请输入最大结转天数', trigger: 'blur' }],
  startTime: [{
    required: true,
    message: '请选择开始时间',
  startTime: [{
    required: true,
    message: '请选择开始时间',
    trigger: 'change',
    validator: (rule, value, callback) => {
      if (!value) {
@@ -334,9 +386,9 @@
      }
    }
  }],
  endTime: [{
    required: true,
    message: '请选择结束时间',
  endTime: [{
    required: true,
    message: '请选择结束时间',
    trigger: 'change',
    validator: (rule, value, callback) => {
      if (!value) {
@@ -346,9 +398,9 @@
      }
    }
  }],
  workStartTime: [{
    required: true,
    message: '请选择上班时间',
  workStartTime: [{
    required: true,
    message: '请选择上班时间',
    trigger: 'change',
    validator: (rule, value, callback) => {
      if (!value) {
@@ -358,9 +410,9 @@
      }
    }
  }],
  workEndTime: [{
    required: true,
    message: '请选择下班时间',
  workEndTime: [{
    required: true,
    message: '请选择下班时间',
    trigger: 'change',
    validator: (rule, value, callback) => {
      if (!value) {
@@ -389,6 +441,27 @@
    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 = () => {
@@ -424,12 +497,12 @@
      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
@@ -470,7 +543,7 @@
  try {
    currentType.value = type
    currentAction.value = action
    if (action === 'add') {
      dialogTitle.value = `新增${getTypeName(type)}`
      currentEditId.value = ''
@@ -480,7 +553,7 @@
      currentEditId.value = row.id
      fillForm(row)
    }
    dialogVisible.value = true
  } catch (error) {
    console.error('打开弹窗失败:', error)
@@ -568,15 +641,15 @@
      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) {
@@ -670,7 +743,7 @@
const editItem = () => {
  let dataArray
  let index
  if (currentType.value === 'holiday') {
    const params = {
      id: currentEditId.value,
@@ -729,7 +802,7 @@
    // dataArray = overtimeData.value
    // index = dataArray.findIndex(item => item.id === currentEditId.value)
    // if (index > -1) {
    //   dataArray[index] = {
    //   dataArray[index] = {
    //     ...dataArray[index],
    //     name: form.name,
    //     type: form.type,
@@ -760,7 +833,7 @@
    // dataArray = worktimeData.value
    // index = dataArray.findIndex(item => item.id === currentEditId.value)
    // if (index > -1) {
    //   dataArray[index] = {
    //   dataArray[index] = {
    //     ...dataArray[index],
    //     name: form.name,
    //     startTime: form.workStartTime || '',
@@ -771,6 +844,253 @@
    //   }
    // }
  }
}
// 打卡记录过滤功能
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
}
// 删除项目
@@ -830,7 +1150,7 @@
        ElMessage.error(err.msg);
      })
    }
    // const index = dataArray.findIndex(item => item.id === row.id)
    // if (index > -1) {
    //   dataArray.splice(index, 1)
@@ -888,6 +1208,7 @@
  getAnnualLeaveSettingList()
  getOvertimeSettingList()
  getWorkingHoursSettingList()
  initAttendanceData()
  console.log('考勤管理页面加载完成')
})