From 96dd34f77d81db58f54e3d0ad4a8cc8082189a61 Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期四, 16 四月 2026 13:52:27 +0800
Subject: [PATCH] 考勤相关更改

---
 src/views/OfficeRelated/checkingIn/components/AttendanceCalendar.vue |  621 ++++++++++----------------------------------------------
 1 files changed, 113 insertions(+), 508 deletions(-)

diff --git a/src/views/OfficeRelated/checkingIn/components/AttendanceCalendar.vue b/src/views/OfficeRelated/checkingIn/components/AttendanceCalendar.vue
index c43976e..f0e23d1 100644
--- a/src/views/OfficeRelated/checkingIn/components/AttendanceCalendar.vue
+++ b/src/views/OfficeRelated/checkingIn/components/AttendanceCalendar.vue
@@ -1,588 +1,193 @@
 <template>
   <div class="attendance-calendar">
-    <!-- 鏃ュ巻澶撮儴缁熻淇℃伅 -->
-    <div class="calendar-stats">
-      <div class="stat-item">
-        <span class="stat-dot present"></span>
-        <span>姝e父鍑哄嫟: {{ stats.presentDays }}澶�</span>
-      </div>
-      <div class="stat-item">
-        <span class="stat-dot absent"></span>
-        <span>缂哄嫟/寮傚父: {{ stats.absentDays }}澶�</span>
-      </div>
-      <div class="stat-item">
-        <span class="stat-dot trip"></span>
-        <span>鍑哄樊: {{ stats.tripDays }}澶�</span>
-      </div>
-      <div class="stat-item">
-        <span class="stat-dot late"></span>
-        <span>杩熷埌/鏃╅��: {{ stats.lateDays }}澶�</span>
-      </div>
-    </div>
+    <!-- <el-button @click="refreshCalendar" size="small" type="primary"
+      >鍒锋柊</el-button
+    > -->
 
-    <!-- Element UI 鏃ュ巻缁勪欢 -->
-    <el-calendar v-model="calendarValue" :first-day-of-week="1">
-      <template #date-cell="{ data }">
-        <div
-          class="calendar-date"
-          :class="getDateStatusClass(data.day)"
-          @click="handleDateClick(data)"
-        >
-          <div class="date-number">{{ data.day.split('-')[2] }}</div>
-
-          <!-- 鐘舵�佽儗鏅壊鍧� -->
-          <div class="status-background" :class="getBackgroundStatus(data.day)"></div>
-
+    <!-- Element UI 鐨勬棩鍘嗙粍浠� -->
+    <el-calendar v-model="value">
+      <template slot="dateCell" slot-scope="{ date, data }">
+        <div class="calendar-date">
+          <div class="date-number">
+            {{
+              data.day
+                .split("-")
+                .slice(1)
+                .join("-")
+            }}
+          </div>
+          <!-- <div style="font-size: 10px; color: #666;">{{ data.day }}</div> -->
           <div class="date-events">
-            <!-- 鍑哄嫟鐘舵�佹爣璁� -->
-            <div v-if="getAttendanceStatus(data.day) !== 'absent'" class="status-mark">
-              <el-tooltip
-                :content="getAttendanceTooltip(data.day)"
-                placement="top"
-              >
-                <span class="status-dot" :class="getAttendanceStatus(data.day)"></span>
-              </el-tooltip>
-            </div>
-
-            <!-- 鍑哄樊鏍囪 -->
-            <div v-if="hasBusinessTrip(data.day)" class="trip-mark">
-              <el-tooltip content="鍑哄樊" placement="top">
-                <i class="el-icon-location-outline"></i>
-              </el-tooltip>
-            </div>
-
-            <!-- 缂哄嫟鏍囪 -->
-            <div v-if="getAttendanceStatus(data.day) === 'absent'" class="absent-mark">
-              <el-tooltip content="缂哄嫟" placement="top">
-                <i class="el-icon-close"></i>
-              </el-tooltip>
-            </div>
-          </div>
-
-          <!-- 绠�鐣ヤ俊鎭樉绀� -->
-          <div class="brief-info">
-            <div v-if="getAttendanceStatus(data.day) === 'present'" class="info-item present-info">
-              鈭�
-            </div>
-            <div v-else-if="getAttendanceStatus(data.day) === 'late'" class="info-item late-info">
-              !
-            </div>
-            <div v-else-if="getAttendanceStatus(data.day) === 'absent'" class="info-item absent-info">
-              脳
-            </div>
-            <div v-if="hasBusinessTrip(data.day)" class="info-item trip-info">
-              鉁�
-            </div>
-          </div>
-
-          <!-- 鏃ユ湡璇︾粏淇℃伅锛堟偓娴樉绀猴級 -->
-          <div class="date-details">
+            <!-- Element UI 涓娇鐢ㄦ彃妲戒綔鐢ㄥ煙 -->
             <div
               v-for="event in getDateEvents(data.day)"
               :key="event.id"
-              class="detail-item"
+              class="event-item"
+              :class="event.type"
             >
-              <span class="detail-type">{{ event.type === 'attendance' ? '鍑哄嫟' : '鍑哄樊' }}</span>
-              <span class="detail-info">{{ event.text }}</span>
-            </div>
-            <div v-if="getDateEvents(data.day).length === 0" class="detail-item">
-              <span class="detail-type">鏃犺褰�</span>
+              <span class="event-dot"></span>
+              <span class="event-text">{{ event.text }}</span>
             </div>
           </div>
         </div>
       </template>
     </el-calendar>
-
-    <!-- 鏃ユ湡璇︽儏瀵硅瘽妗� -->
-    <el-dialog
-      :title="`${selectedDate} 鑰冨嫟璇︽儏`"
-      v-model="detailDialogVisible"
-      width="500px"
-    >
-      <div v-if="selectedDateInfo">
-        <div class="detail-section">
-          <h4>鍑哄嫟淇℃伅</h4>
-          <div v-if="selectedDateInfo.attendance">
-            <p>涓婄彮鏃堕棿: {{ selectedDateInfo.attendance.checkIn || '鏈墦鍗�' }}</p>
-            <p>涓嬬彮鏃堕棿: {{ selectedDateInfo.attendance.checkOut || '鏈墦鍗�' }}</p>
-            <p>鐘舵��:
-              <el-tag :type="getStatusTagType(selectedDateInfo.attendance.status)">
-                {{ getStatusText(selectedDateInfo.attendance.status) }}
-              </el-tag>
-            </p>
-          </div>
-          <div v-else>
-            <p class="no-data">鏃犲嚭鍕よ褰�</p>
-          </div>
-        </div>
-
-        <div class="detail-section" v-if="selectedDateInfo.businessTrip">
-          <h4>鍑哄樊淇℃伅</h4>
-          <p>鐩殑鍦�: {{ selectedDateInfo.businessTrip.destination }}</p>
-          <p>浜嬬敱: {{ selectedDateInfo.businessTrip.reason }}</p>
-          <p>閲岀▼: {{ selectedDateInfo.businessTrip.distance }}鍏噷</p>
-        </div>
-      </div>
-      <template #footer>
-        <el-button @click="detailDialogVisible = false">鍏抽棴</el-button>
-      </template>
-    </el-dialog>
   </div>
 </template>
 
 <script>
 export default {
-  name: 'AttendanceCalendar',
+  name: "AttendanceCalendar",
   props: {
-    attendanceData: {
-      type: Array,
-      default: () => []
-    },
-    businessTripData: {
-      type: Array,
-      default: () => []
-    }
+    attendanceData: Array,
+    businessTripData: Array
   },
   data() {
     return {
-      calendarValue: new Date(),
-      detailDialogVisible: false,
-      selectedDate: '',
-      selectedDateInfo: null,
-      stats: {
-        presentDays: 0,
-        absentDays: 0,
-        tripDays: 0,
-        lateDays: 0
+      value: new Date(), // Element UI 浣跨敤 value
+      localAttendanceData: [],
+      localBusinessTripData: []
+    };
+  },
+  watch: {
+    attendanceData: {
+      immediate: true,
+      handler(val) {
+        this.localAttendanceData = val || [];
+        console.log("鑰冨嫟鏁版嵁:", this.localAttendanceData);
+        this.$nextTick(() => {
+          this.$forceUpdate(); // Vue 2 鐨勫己鍒舵洿鏂�
+        });
+      }
+    },
+    businessTripData: {
+      immediate: true,
+      handler(val) {
+        this.localBusinessTripData = val || [];
+        console.log("鍑哄樊鏁版嵁:", this.localBusinessTripData);
+        this.$nextTick(() => {
+          this.$forceUpdate();
+        });
       }
     }
   },
   mounted() {
-    this.calculateStats()
-  },
-  watch: {
-    attendanceData: {
-      handler() {
-        this.calculateStats()
-      },
-      deep: true
-    },
-    businessTripData: {
-      handler() {
-        this.calculateStats()
-      },
-      deep: true
-    }
+    console.log("Calendar mounted with Vue 2.6.12");
+    this.testMethod();
   },
   methods: {
-    // 鑾峰彇鏃ユ湡鐘舵�佺被鍚�
-    getDateStatusClass(date) {
-      const classes = []
-      if (this.isToday(date)) {
-        classes.push('today')
-      }
-      if (this.isSelected(date)) {
-        classes.push('selected')
-      }
-
-      // 娣诲姞鐘舵�佺被鍚�
-      const status = this.getBackgroundStatus(date)
-      if (status) {
-        classes.push(status)
-      }
-
-      return classes
+    refreshCalendar() {
+      console.log("鎵嬪姩鍒锋柊鏃ュ巻");
+      this.$forceUpdate();
     },
-
-    // 鑾峰彇鑳屾櫙鐘舵�侊紙鐢ㄤ簬鑳屾櫙鑹诧級
-    getBackgroundStatus(date) {
-      const attendance = this.attendanceData.find(item => item.date === date)
-      const hasTrip = this.hasBusinessTrip(date)
-
-      if (hasTrip) {
-        return 'has-trip'
-      }
-
-      if (attendance) {
-        switch (attendance.status) {
-          case 'present': return 'has-attendance'
-          case 'late': return 'has-late'
-          case 'absent': return 'has-absent'
-          default: return ''
-        }
-      }
-
-      return ''
+    testMethod() {
+      console.log("娴嬭瘯鏂规硶鏄惁鍙皟鐢�");
+      console.log("getDateEvents 娴嬭瘯:", this.getDateEvents("2024-01-15"));
     },
-
-    // 鍒ゆ柇鏄惁涓轰粖澶�
-    isToday(date) {
-      const today = new Date()
-      const compareDate = new Date(date)
-      return today.toDateString() === compareDate.toDateString()
-    },
-
-    // 鍒ゆ柇鏄惁琚�変腑
-    isSelected(date) {
-      return this.selectedDate === date
-    },
-
-    // 鑾峰彇鑰冨嫟鐘舵��
-    getAttendanceStatus(date) {
-      const attendance = this.attendanceData.find(item => item.date === date)
-      if (!attendance) return 'absent'
-
-      switch (attendance.status) {
-        case 'present': return 'present'
-        case 'late': return 'late'
-        case 'absent': return 'absent'
-        default: return 'absent'
-      }
-    },
-
-    // 鑾峰彇鐘舵�佹枃鏈�
-    getStatusText(status) {
-      const statusMap = {
-        present: '姝e父鍑哄嫟',
-        late: '杩熷埌/鏃╅��',
-        absent: '缂哄嫟/寮傚父'
-      }
-      return statusMap[status] || '鏈煡鐘舵��'
-    },
-
-    // 鑾峰彇鑰冨嫟鐘舵�佹彁绀�
-    getAttendanceTooltip(date) {
-      const statusMap = {
-        present: '姝e父鍑哄嫟',
-        late: '杩熷埌/鏃╅��',
-        absent: '缂哄嫟/寮傚父'
-      }
-      return statusMap[this.getAttendanceStatus(date)] || '鏃犺褰�'
-    },
-
-    // 鍒ゆ柇鏄惁鏈夊嚭宸�
-    hasBusinessTrip(date) {
-      return this.businessTripData.some(item =>
-        date >= item.startDate && date <= item.endDate
-      )
-    },
-
-    // 鑾峰彇鏃ユ湡浜嬩欢
     getDateEvents(date) {
-      const events = []
-      const attendance = this.attendanceData.find(item => item.date === date)
+      console.log("getDateEvents 琚皟鐢�, 鏃ユ湡:", date);
+      console.log("褰撳墠鑰冨嫟鏁版嵁:", this.localAttendanceData);
+      console.log("褰撳墠鍑哄樊鏁版嵁:", this.localBusinessTripData);
+
+      const events = [];
+
+      // 鑰冨嫟鏁版嵁
+      const attendance = (this.localAttendanceData || []).find(item => {
+        return item && item.date === date;
+      });
 
       if (attendance) {
         events.push({
           id: `attendance-${date}`,
-          type: 'attendance',
-          text: `${attendance.checkIn || '鏈墦鍗�'} - ${attendance.checkOut || '鏈墦鍗�'}`
-        })
+          type: "attendance",
+          text: `${attendance.checkIn || "--"}-${attendance.checkOut || "--"}`
+        });
       }
 
-      const businessTrip = this.businessTripData.find(item =>
-        date >= item.startDate && date <= item.endDate
-      )
+      // 鍑哄樊鏁版嵁
+      const businessTrip = (this.localBusinessTripData || []).find(item => {
+        return item && date >= item.startDate && date <= item.endDate;
+      });
+
       if (businessTrip) {
         events.push({
           id: `business-trip-${date}`,
-          type: 'businessTrip',
-          text: `鍓嶅線${businessTrip.destination}`
-        })
+          type: "business-trip",
+          text: `鍑哄樊: ${businessTrip.endCity || ""}`
+        });
       }
 
-      return events
-    },
-
-    // 澶勭悊鏃ユ湡鐐瑰嚮浜嬩欢
-    handleDateClick(data) {
-      this.selectedDate = data.day
-      this.selectedDateInfo = {
-        attendance: this.attendanceData.find(item => item.date === data.day),
-        businessTrip: this.businessTripData.find(item =>
-          data.day >= item.startDate && data.day <= item.endDate
-        )
-      }
-      this.detailDialogVisible = true
-    },
-
-    // 鑾峰彇鐘舵�佹爣绛剧被鍨�
-    getStatusTagType(status) {
-      const typeMap = {
-        present: 'success',
-        late: 'warning',
-        absent: 'danger'
-      }
-      return typeMap[status] || 'info'
-    },
-
-    // 璁$畻缁熻淇℃伅
-    calculateStats() {
-      // 閲嶇疆缁熻
-      this.stats = { presentDays: 0, absentDays: 0, tripDays: 0, lateDays: 0 }
-
-      this.attendanceData.forEach(item => {
-        switch (item.status) {
-          case 'present': this.stats.presentDays++; break
-          case 'late': this.stats.lateDays++; break
-          case 'absent': this.stats.absentDays++; break
-        }
-      })
-
-      // 璁$畻鍑哄樊澶╂暟
-      const tripDays = new Set()
-      this.businessTripData.forEach(item => {
-        const start = new Date(item.startDate)
-        const end = new Date(item.endDate)
-        for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
-          tripDays.add(d.toISOString().split('T')[0])
-        }
-      })
-      this.stats.tripDays = tripDays.size
+      console.log("鎵惧埌鐨勪簨浠�:", events);
+      return events;
     }
   }
-}
+};
 </script>
 
 <style scoped>
 .attendance-calendar {
   padding: 20px;
-  max-width: 100%;
 }
-
-.calendar-stats {
-  display: flex;
-  justify-content: space-around;
-  margin-bottom: 20px;
-  padding: 15px;
-  background: #f5f7fa;
-  border-radius: 8px;
-}
-
-.stat-item {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-}
-
-.stat-dot {
-  width: 12px;
-  height: 12px;
-  border-radius: 50%;
-  display: inline-block;
-}
-
-.stat-dot.present { background-color: #67c23a; }
-.stat-dot.absent { background-color: #f56c6c; }
-.stat-dot.trip { background-color: #409eff; }
-.stat-dot.late { background-color: #e6a23c; }
 
 .calendar-date {
-  height: 80px;
-  padding: 4px;
-  border: 1px solid #ebeef5;
-  border-radius: 4px;
-  cursor: pointer;
-  transition: all 0.3s;
-  position: relative;
-  overflow: hidden;
-}
-
-.calendar-date:hover {
-  background-color: #f0f9ff;
-  border-color: #409eff;
-  transform: translateY(-2px);
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-}
-
-.calendar-date.today {
-  border-color: #409eff;
-  background-color: #f0f9ff;
-}
-
-.calendar-date.selected {
-  background-color: #ecf5ff;
-  border-color: #409eff;
-}
-
-/* 鐘舵�佽儗鏅壊 */
-.status-background {
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  opacity: 0.1;
-  z-index: 0;
-}
-
-.calendar-date.has-attendance .status-background {
-  background-color: #67c23a;
-}
-
-.calendar-date.has-late .status-background {
-  background-color: #e6a23c;
-}
-
-.calendar-date.has-absent .status-background {
-  background-color: #f56c6c;
-}
-
-.calendar-date.has-trip .status-background {
-  background: linear-gradient(135deg, #409eff 0%, #67c23a 100%);
+  height: 100%;
+  padding: 8px;
+  display: flex;
+  flex-direction: column;
 }
 
 .date-number {
   font-weight: bold;
-  font-size: 14px;
-  margin-bottom: 2px;
-  position: relative;
-  z-index: 1;
+  margin-bottom: 4px;
+  font-size: 16px;
 }
 
 .date-events {
-  display: flex;
-  flex-direction: column;
-  gap: 2px;
-  position: relative;
-  z-index: 1;
+  flex: 1;
+  overflow: hidden;
 }
 
-.status-mark, .trip-mark, .absent-mark {
+.event-item {
   display: flex;
   align-items: center;
-  gap: 4px;
+  margin-bottom: 2px;
+  font-size: 12px;
+  padding: 2px 4px;
+  border-radius: 2px;
+  background-color: #f5f7fa;
 }
 
-.status-dot {
-  width: 8px;
-  height: 8px;
-  border-radius: 50%;
-  display: inline-block;
+.event-item.attendance {
+  background-color: #f0f9eb;
+  color: #67c23a;
 }
 
-.status-dot.present { background-color: #67c23a; }
-.status-dot.late { background-color: #e6a23c; }
-.status-dot.absent { background-color: #f56c6c; }
-
-.trip-mark i {
+.event-item.business-trip {
+  background-color: #ecf5ff;
   color: #409eff;
-  font-size: 12px;
 }
 
-.absent-mark i {
-  color: #f56c6c;
-  font-size: 12px;
-}
-
-/* 绠�鐣ヤ俊鎭樉绀� */
-.brief-info {
-  position: absolute;
-  bottom: 4px;
-  right: 4px;
-  display: flex;
-  gap: 2px;
-  z-index: 1;
-}
-
-.info-item {
-  width: 16px;
-  height: 16px;
+.event-dot {
+  width: 6px;
+  height: 6px;
   border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 10px;
-  font-weight: bold;
-}
-
-.present-info {
-  background-color: #67c23a;
-  color: white;
-}
-
-.late-info {
-  background-color: #e6a23c;
-  color: white;
-}
-
-.absent-info {
-  background-color: #f56c6c;
-  color: white;
-}
-
-.trip-info {
-  background-color: #409eff;
-  color: white;
-}
-
-.date-details {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  right: 0;
-  background: white;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  padding: 8px;
-  z-index: 1000;
-  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-  display: none;
-}
-
-.calendar-date:hover .date-details {
-  display: block;
-}
-
-.detail-item {
-  font-size: 12px;
-  margin-bottom: 4px;
-  display: flex;
-  align-items: center;
-}
-
-.detail-type {
-  font-weight: bold;
   margin-right: 4px;
-  min-width: 40px;
 }
 
-.detail-info {
-  color: #606266;
+.event-item.attendance .event-dot {
+  background-color: #67c23a;
 }
 
-.detail-section {
-  margin-bottom: 20px;
+.event-item.business-trip .event-dot {
+  background-color: #409eff;
 }
-
-.detail-section h4 {
-  margin-bottom: 10px;
-  color: #303133;
-  border-left: 4px solid #409eff;
-  padding-left: 8px;
+::v-deep .el-calendar-table .el-calendar-day {
+  height: 115px;
 }
-
-.no-data {
-  color: #909399;
-  font-style: italic;
-}
-
-:deep(.el-calendar__header) {
-  padding: 10px;
-  border-bottom: 1px solid #ebeef5;
-}
-
-:deep(.el-calendar-day) {
-  padding: 0 !important;
-  height: 80px;
-}
-
-:deep(.el-calendar-table:not(.is-range) td) {
-  border: 1px solid #f0f0f0;
-}
-
-:deep(.el-calendar-table .el-calendar-day) {
-  height: 80px !important;
-  padding: 0 !important;
+.event-text {
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  flex: 1;
 }
 </style>

--
Gitblit v1.9.3