zhangwencui
3 天以前 9c83f21a3e781ab5520b5eb7ddfe35c3638a9a21
src/pages/humanResources/attendance/report.vue
@@ -26,33 +26,43 @@
                        @cancel="showDatePicker = false"
                        title="搜索日期" />
    <view class="record-list">
      <view v-for="(item) in tableData"
      <!-- 加载状态 -->
      <view v-if="loading"
            class="loading-state">
        <u-icon name="loading"
                size="40"
                color="#348fe2"></u-icon>
        <text class="loading-text">加载中...</text>
      </view>
      <view v-else
            v-for="(item) in tableData"
            :key="item.id"
            class="record-item-card"
            :class="{ 'abnormal': item.status !== 'normal' }">
            :class="{ 'abnormal': item.status !== 0 }">
        <view class="record-item-header">
          <text class="record-date">{{ item.date }}</text>
          <u-tag :type="item.status === 'normal' ? 'success' : 'error'"
          <u-tag :type="item.status === 0 ? 'success' : 'error'"
                 size="small">
            {{ item.statusText }}
            <!-- {{ item.status === 0 ? '正常' : (item.status === 1 ? '迟到' : (item.status === 2 ? '早退' : '迟到、早退')) }} -->
            {{ getStatusText(item.status) }}
          </u-tag>
        </view>
        <view class="record-item-body">
          <view class="record-detail">
            <text class="detail-label">员工</text>
            <text class="detail-value">{{ item.name }} ({{ item.no }})</text>
            <text class="detail-value">{{ item.staffName }} ({{ item.staffNo }})</text>
          </view>
          <view class="record-detail">
            <text class="detail-label">部门</text>
            <text class="detail-value">{{ item.dept }}</text>
            <text class="detail-value">{{ item.deptName }}</text>
          </view>
          <view class="record-detail">
            <text class="detail-label">上班时间</text>
            <text class="detail-value">{{ item.checkInTime ? item.checkInTime : '缺卡' }}</text>
            <text class="detail-value">{{ item.workStartAt || '缺卡' }}</text>
          </view>
          <view class="record-detail">
            <text class="detail-label">下班时间</text>
            <text class="detail-value">{{ item.checkOutTime? item.checkOutTime : '缺卡' }}</text>
            <text class="detail-value">{{ item.workEndAt || '缺卡' }}</text>
          </view>
          <view class="record-detail">
            <text class="detail-label">工时</text>
@@ -66,11 +76,11 @@
        </view>
      </view>
      <!-- 空状态 -->
      <view v-if="tableData.length === 0"
      <view v-if="tableData.length === 0 && !loading"
            class="empty-state">
        <u-icon name="clock-o"
        <!-- <u-icon name="clock-o"
                size="60"
                color="#999"></u-icon>
                color="#999"></u-icon> -->
        <text class="empty-text">暂无考勤记录</text>
      </view>
    </view>
@@ -89,96 +99,25 @@
  import { ref, reactive, onMounted } from "vue";
  import PageHeader from "@/components/PageHeader.vue";
  import dayjs from "dayjs";
  // 模拟当前登录员工
  const currentUser = reactive({
    id: 1,
    name: "张三",
    no: "E10001",
    dept: "生产一部",
  });
  // 模拟考勤原始数据
  const rawAttendance = ref([
    {
      id: 1,
      date: "2026-02-09",
      userId: 1,
      name: "张三",
      no: "E10001",
      dept: "生产一部",
      checkInTime: "08:58",
      checkOutTime: "",
      workHours: null,
      status: "normal",
      statusText: "正常",
      remark: "",
    },
    {
      id: 2,
      date: "2026-02-08",
      userId: 1,
      name: "张三",
      no: "E10001",
      dept: "生产一部",
      checkInTime: "09:15",
      checkOutTime: "18:05",
      workHours: 8.8,
      status: "late",
      statusText: "迟到",
      remark: "因交通拥堵迟到",
    },
    {
      id: 3,
      date: "2026-02-07",
      userId: 1,
      name: "张三",
      no: "E10001",
      dept: "生产一部",
      checkInTime: "08:45",
      checkOutTime: "18:30",
      workHours: 9.7,
      status: "normal",
      statusText: "正常",
      remark: "加班0.5小时",
    },
    {
      id: 4,
      date: "2026-02-06",
      userId: 1,
      name: "张三",
      no: "E10001",
      dept: "生产一部",
      checkInTime: "08:50",
      checkOutTime: "17:45",
      workHours: 8.9,
      status: "early",
      statusText: "早退",
      remark: "家中有事提前离开",
    },
    {
      id: 5,
      date: "2026-02-05",
      userId: 1,
      name: "张三",
      no: "E10001",
      dept: "生产一部",
      checkInTime: "08:40",
      checkOutTime: "18:20",
      workHours: 9.7,
      status: "normal",
      statusText: "正常",
      remark: "加班0.5小时",
    },
  ]);
  import { findPersonalAttendanceRecords } from "@/api/personnelManagement/attendance.js";
  // 查询表单
  const searchForm = reactive({
    date: "",
  });
  // 分页参数
  const page = reactive({
    current: -1,
    size: -1,
    total: 0,
  });
  // 表格数据
  const tableData = ref([]);
  // 加载状态
  const loading = ref(false);
  // 返回上一页
  const goBack = () => {
@@ -196,6 +135,20 @@
    showDatePicker.value = false;
    handleQuery();
  };
  const getStatusText = status => {
    switch (status) {
      case 0:
        return "正常";
      case 1:
        return "迟到";
      case 2:
        return "早退";
      case 3:
        return "迟到、早退";
      case 4:
        return "缺勤";
    }
  };
  // 显示日期选择器
  const selectDate = () => {
@@ -204,27 +157,42 @@
  // 清除日期选择
  const clearDate = () => {
    resetQuery();
  };
  // 查询
  const handleQuery = () => {
    loading.value = true;
    console.log(searchForm, "searchForm");
    findPersonalAttendanceRecords({
      ...page,
      ...searchForm,
    })
      .then(res => {
        tableData.value = res.data.records;
        page.total = res.data.total;
      })
      .catch(error => {
        console.error("查询失败:", error);
        uni.showToast({
          title: "查询失败,请重试",
          icon: "none",
        });
      })
      .finally(() => {
        loading.value = false;
      });
  };
  // 重置查询
  const resetQuery = () => {
    searchForm.date = "";
    handleQuery();
  };
  // 查询
  const recomputeTable = () => {
    const list = rawAttendance.value.filter(item => {
      if (searchForm.date && item.date !== searchForm.date) {
        return false;
      }
      return true;
    });
    tableData.value = list;
  };
  const handleQuery = () => {
    recomputeTable();
  };
  onMounted(() => {
    recomputeTable();
    handleQuery();
  });
</script>
@@ -307,6 +275,24 @@
    margin: 0 20rpx 24rpx;
  }
  /* 加载状态 */
  .loading-state {
    background-color: $card-bg;
    border-radius: 16rpx;
    box-shadow: $shadow-md;
    text-align: center;
    padding: 120rpx 0;
    margin: 0 20rpx;
    transition: all 0.3s ease;
  }
  .loading-text {
    font-size: 14px;
    color: $text-tertiary;
    margin-top: 24rpx;
    font-weight: 500;
  }
  .record-item-card {
    background-color: $card-bg;
    border-radius: 16rpx;