按照日期分配课程

<template>
  <div class="container">
    <!-- 左侧课程列表 -->
    <div class="course-list">
      <div 
        v-for="course in courses" 
        :key="course.id"
        class="course-item"
        draggable="true"
        @dragstart="handleDragStart($event, course)"
      >
        {{ course.name }}
      </div>
    </div>

    <!-- 右侧可滑动课程表 -->
    <div class="schedule-wrapper">
      <div class="schedule-container" ref="scheduleContainer">
        <div 
          v-for="(day, dayIdx) in visibleDays" 
          :key="day.date"
          class="day-column"
        >
          <div class="day-header">{{ day.formattedDate }}</div>
          <div
            v-for="(slot, slotIdx) in timeSlots"
            :key="slot"
            class="time-slot"
            :class="{
              'active-cell': activeCell.day === dayIdx && activeCell.slot === slotIdx,
              'has-course': day.slots[slotIdx].course
            }"
            @dragover.prevent="handleDragOver(dayIdx, slotIdx)"
            @dragleave="handleDragLeave"
            @drop="handleDrop($event, dayIdx, slotIdx)"
          >
            {{ slot }}
            <div v-if="day.slots[slotIdx].course" class="course-name">
              {{ day.slots[slotIdx].course.name }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';

// 课程数据
const courses = ref([
  { id: 1, name: '数学课', color: '#ffeb3b' },
  { id: 2, name: '英语课', color: '#4caf50' },
  { id: 3, name: '物理课', color: '#2196f3' }
]);

// 时间槽配置
const timeSlots = ref([
  '08:00', '09:00', '10:00', 
  '11:00', '14:00', '15:00'
]);

// 可见日期(示例生成一周)
const visibleDays = reactive([]);

// 拖拽相关状态
const draggedCourse = ref(null);
const activeCell = reactive({ day: null, slot: null });

// 初始化课程表数据
const initializeSchedule = () => {
  const days = [];
  const today = new Date();
  
  for (let i = 0; i < 7; i++) {
    const date = new Date(today);
    date.setDate(today.getDate() + i);
    
    days.push({
      date: date.toISOString(),
      formattedDate: date.toLocaleDateString('zh-CN', { 
        month: '2-digit', 
        day: '2-digit' 
      }),
      slots: timeSlots.value.map(() => ({ course: null }))
    });
  }
  
  visibleDays.push(...days);
};

// 拖拽开始
const handleDragStart = (e, course) => {
  draggedCourse.value = course;
  e.dataTransfer.setData('text/plain', course.id);
  e.dataTransfer.effectAllowed = 'move';
};

// 拖拽经过
const handleDragOver = (dayIdx, slotIdx) => {
  activeCell.day = dayIdx;
  activeCell.slot = slotIdx;
};

// 拖拽离开
const handleDragLeave = () => {
  activeCell.day = null;
  activeCell.slot = null;
};

// 拖拽释放
const handleDrop = (e, dayIdx, slotIdx) => {
  const courseId = e.dataTransfer.getData('text/plain');
  const course = courses.value.find(c => c.id == courseId);
  
  if (course) {
    visibleDays[dayIdx].slots[slotIdx].course = course;
  }
  
  handleDragLeave();
};

onMounted(initializeSchedule);
</script>

<style scoped>
.container {
  display: flex;
  height: 100vh;
  background: #f5f5f5;
}

.course-list {
  width: 200px;
  padding: 20px;
  background: white;
  border-right: 1px solid #ddd;
}

.course-item {
  padding: 12px;
  margin-bottom: 8px;
  background: #fff;
  border: 1px solid #eee;
  border-radius: 4px;
  cursor: move;
  transition: all 0.2s;
}

.course-item:hover {
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.schedule-wrapper {
  flex: 1;
  overflow-x: auto;
  padding: 20px;
}

.schedule-container {
  display: flex;
  gap: 20px;
  min-width: fit-content;
}

.day-column {
  width: 180px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.day-header {
  padding: 12px;
  background: #f8f9fa;
  border-bottom: 1px solid #eee;
  text-align: center;
  font-weight: 500;
}

.time-slot {
  height: 80px;
  padding: 8px;
  border-bottom: 1px solid #f0f0f0;
  position: relative;
  transition: all 0.2s;
}

.time-slot.active-cell {
  background: #e3f2fd;
  box-shadow: inset 0 0 0 2px #2196f3;
}

.time-slot.has-course {
  background: #f0f4c3;
}

.course-name {
  margin-top: 4px;
  font-size: 12px;
  color: #666;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值