From 4071a902f383275b7ed284876bbdf3e19cfa3522 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期一, 09 二月 2026 18:02:15 +0800
Subject: [PATCH] Merge branch 'dev_new' of http://114.132.189.42:9002/r/product-inventory-APP-before into dev_new
---
src/pages/attendance/report.vue | 446 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 446 insertions(+), 0 deletions(-)
diff --git a/src/pages/attendance/report.vue b/src/pages/attendance/report.vue
new file mode 100644
index 0000000..7d50294
--- /dev/null
+++ b/src/pages/attendance/report.vue
@@ -0,0 +1,446 @@
+<template>
+ <view class="attendance-report">
+ <!-- 椤甸潰澶撮儴 -->
+ <PageHeader title="鑰冨嫟鏃ユ姤"
+ @back="goBack" />
+ <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+ <view class="search-section">
+ <view class="search-bar">
+ <view @click="selectDate"
+ class="search-input">
+ <view class="search-text">{{ searchForm.date? searchForm.date : '璇烽�夋嫨鏃ユ湡' }}</view>
+ </view>
+ <view class="filter-button"
+ @click="clearDate">
+ <u-icon name="close-circle"
+ size="24"
+ color="#999"></u-icon>
+ </view>
+ </view>
+ </view>
+ <!-- 鏃ユ湡閫夋嫨鍣� -->
+ <up-datetime-picker :show="showDatePicker"
+ mode="date"
+ v-model="currentDate"
+ @confirm="handleDateConfirm"
+ @cancel="showDatePicker = false"
+ title="鎼滅储鏃ユ湡" />
+ <view class="record-list">
+ <view v-for="(item) in tableData"
+ :key="item.id"
+ class="record-item-card"
+ :class="{ 'abnormal': item.status !== 'normal' }">
+ <view class="record-item-header">
+ <text class="record-date">{{ item.date }}</text>
+ <u-tag :type="item.status === 'normal' ? 'success' : 'error'"
+ size="small">
+ {{ item.statusText }}
+ </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>
+ </view>
+ <view class="record-detail">
+ <text class="detail-label">閮ㄩ棬</text>
+ <text class="detail-value">{{ item.dept }}</text>
+ </view>
+ <view class="record-detail">
+ <text class="detail-label">涓婄彮鏃堕棿</text>
+ <text class="detail-value">{{ item.checkInTime ? item.checkInTime : '缂哄崱' }}</text>
+ </view>
+ <view class="record-detail">
+ <text class="detail-label">涓嬬彮鏃堕棿</text>
+ <text class="detail-value">{{ item.checkOutTime? item.checkOutTime : '缂哄崱' }}</text>
+ </view>
+ <view class="record-detail">
+ <text class="detail-label">宸ユ椂</text>
+ <text class="detail-value">{{ item.workHours ? item.workHours + '灏忔椂' : '-' }}</text>
+ </view>
+ <view v-if="item.remark"
+ class="record-detail">
+ <text class="detail-label">澶囨敞</text>
+ <text class="detail-value">{{ item.remark }}</text>
+ </view>
+ </view>
+ </view>
+ <!-- 绌虹姸鎬� -->
+ <view v-if="tableData.length === 0"
+ class="empty-state">
+ <u-icon name="clock-o"
+ size="60"
+ color="#999"></u-icon>
+ <text class="empty-text">鏆傛棤鑰冨嫟璁板綍</text>
+ </view>
+ </view>
+ <!-- 瀵煎嚭鎸夐挳 -->
+ <!-- <view class="export-section">
+ <u-button type="default"
+ size="medium"
+ text="瀵煎嚭鑰冨嫟鏃ユ姤"
+ @click="handleExport"
+ class="export-btn"></u-button>
+ </view> -->
+ </view>
+</template>
+
+<script setup>
+ 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: "姝e父",
+ 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: "姝e父",
+ 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: "姝e父",
+ remark: "鍔犵彮0.5灏忔椂",
+ },
+ ]);
+
+ // 鏌ヨ琛ㄥ崟
+ const searchForm = reactive({
+ date: "",
+ });
+
+ // 琛ㄦ牸鏁版嵁
+ const tableData = ref([]);
+
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.navigateBack();
+ };
+
+ // 鏃ユ湡閫夋嫨鍣�
+ const showDatePicker = ref(false);
+ const currentDate = ref(new Date());
+
+ // 澶勭悊鏃ユ湡閫夋嫨
+ const handleDateConfirm = e => {
+ currentDate.value = e.value;
+ searchForm.date = dayjs(e.value).format("YYYY-MM-DD");
+ showDatePicker.value = false;
+ handleQuery();
+ };
+
+ // 鏄剧ず鏃ユ湡閫夋嫨鍣�
+ const selectDate = () => {
+ showDatePicker.value = true;
+ };
+
+ // 娓呴櫎鏃ユ湡閫夋嫨
+ const clearDate = () => {
+ 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();
+ });
+</script>
+
+<style scoped lang="scss">
+ // 鍏ㄥ眬鍙橀噺
+ $primary-color: #2c7be5;
+ $primary-light: #4a90e2;
+ $success-color: #4cd964;
+ $warning-color: #ff9500;
+ $danger-color: #ff3b30;
+ $text-primary: #333333;
+ $text-secondary: #666666;
+ $text-tertiary: #999999;
+ $bg-color: #f5f7fa;
+ $card-bg: #ffffff;
+ $border-color: #e8e8e8;
+ $shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
+ $shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.12);
+ $shadow-lg: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
+
+ .attendance-report {
+ min-height: 100vh;
+ background-color: $bg-color;
+ padding-bottom: 30rpx;
+ background-image: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
+ }
+
+ /* 鎼滅储鍜岀瓫閫夊尯鍩� */
+ .search-section {
+ background-color: $card-bg;
+ margin: 20rpx;
+ border-radius: 16rpx;
+ box-shadow: $shadow-md;
+ padding: 20rpx;
+ margin-bottom: 24rpx;
+ transition: all 0.3s ease;
+ }
+
+ .search-section:hover {
+ box-shadow: $shadow-lg;
+ transform: translateY(-2rpx);
+ }
+
+ .search-bar {
+ display: flex;
+ align-items: center;
+ background-color: rgba($primary-color, 0.05);
+ border-radius: 8rpx;
+ padding: 0 16rpx;
+ height: 70rpx;
+ }
+
+ .search-input {
+ flex: 1;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ }
+
+ .search-text {
+ font-size: 14px;
+ color: $text-tertiary;
+ height: 70rpx;
+ line-height: 70rpx;
+ margin-left: 8rpx;
+ }
+
+ .filter-button {
+ padding: 8rpx;
+ transition: all 0.3s ease;
+ }
+
+ .filter-button:hover {
+ background-color: rgba($primary-color, 0.1);
+ border-radius: 4rpx;
+ }
+
+ /* 璁板綍鍒楄〃 */
+ .record-list {
+ margin: 0 20rpx 24rpx;
+ }
+
+ .record-item-card {
+ background-color: $card-bg;
+ border-radius: 16rpx;
+ box-shadow: $shadow-md;
+ margin-bottom: 24rpx;
+ overflow: hidden;
+ transition: all 0.3s ease;
+ }
+
+ .record-item-card:hover {
+ box-shadow: $shadow-lg;
+ transform: translateY(-2rpx);
+ }
+
+ .record-item-card.abnormal {
+ background-color: rgba($danger-color, 0.05);
+ border-left: 4rpx solid $danger-color;
+ }
+
+ .record-item-header {
+ background-color: rgba($primary-color, 0.05);
+ padding: 20rpx;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1rpx solid $border-color;
+ }
+
+ .record-date {
+ font-size: 14px;
+ font-weight: 600;
+ color: $text-primary;
+ }
+
+ .record-item-body {
+ padding: 24rpx;
+ }
+
+ .record-detail {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16rpx;
+ padding: 8rpx 0;
+ border-bottom: 1rpx solid rgba($border-color, 0.5);
+ }
+
+ .record-detail:last-child {
+ margin-bottom: 0;
+ border-bottom: none;
+ }
+
+ .detail-label {
+ font-size: 13px;
+ color: $text-secondary;
+ font-weight: 500;
+ }
+
+ .detail-value {
+ font-size: 13px;
+ color: $text-primary;
+ font-weight: 500;
+ }
+
+ /* 绌虹姸鎬� */
+ .empty-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;
+ }
+
+ .empty-state:hover {
+ box-shadow: $shadow-lg;
+ }
+
+ .empty-text {
+ font-size: 14px;
+ color: $text-tertiary;
+ margin-top: 24rpx;
+ font-weight: 500;
+ }
+
+ /* 鍝嶅簲寮忚皟鏁� */
+ @media (max-width: 375px) {
+ .search-section,
+ .record-list,
+ .empty-state {
+ margin: 12rpx;
+ }
+
+ .search-section {
+ padding: 16rpx;
+ }
+
+ .record-item-body {
+ padding: 20rpx;
+ }
+ }
+
+ /* 鍔ㄧ敾鏁堟灉 */
+ @keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(20rpx);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+
+ .search-section,
+ .record-item-card,
+ .empty-state {
+ animation: fadeInUp 0.5s ease-out;
+ }
+
+ .record-item-card {
+ animation-delay: 0.1s;
+ }
+
+ .record-item-card:nth-child(2) {
+ animation-delay: 0.2s;
+ }
+
+ .record-item-card:nth-child(3) {
+ animation-delay: 0.3s;
+ }
+
+ .empty-state {
+ animation-delay: 0.2s;
+ }
+</style>
\ No newline at end of file
--
Gitblit v1.9.3