wode-jihua-paike.vue 8.95 KB
<template>
  <view class="paike-wrap">
    <!-- 顶部导航 -->
    <view class="page-header" hover-class="none">
      <view class="nav-bar" :style="{
        paddingTop: menuButtonInfo.top + 'px',
        height: menuButtonInfo.height + 'px'
      }">
        <view class="nav-left" @click="goBack">
          <uni-icons class="back-icon" type="left" size="28" color="#fff"></uni-icons>
        </view>
        <view class="nav-title">计划排课</view>
        <view class="nav-right"></view>
      </view>
    </view>
    <!-- 星期头部:一二三四五六日 -->
    <view class="week-head">
      <view v-for="item in weekText" :key="item" class="week-cell">{{ item }}</view>
    </view>
    <!-- 日历主体容器 -->
    <view class="calendar-box">
      <!-- 月份标题行 -->
      <view v-for="monthItem in monthList" :key="monthItem.month" class="month-wrap">
        <view class="month-title">{{ monthItem.month }}月</view>
        <!-- 当月日期网格 Grid7列 -->
        <view class="date-grid">
          <!-- 前置空白占位格子(当月开头非周一填充空白) -->
          <view v-for="empty in monthItem.emptyCount" :key="'empty' + empty" class="date-cell empty-cell"></view>
          <!-- 有效日期格子 -->
          <view v-for="day in monthItem.dayList" :key="day.day" class="date-cell"
            @click="openTemplateDatil(day.DailyTemplateId, day.year, day.month, day.day)"
            :class="{ hasClass: day.trainName }">
            <!-- 日期数字 -->
            <text class="day-num">{{ day.day }}</text>
            <!-- 黄色排课标签 -->
            <view class="train-label-box">
              <view v-if="day.trainName" class="train-label">{{ day.trainName }}</view>
              <view v-else class="empty-label"></view>
            </view>
          </view>
        </view>
      </view>
    </view>
    <!-- 底部提示文案(适配底部安全区) -->
    <view class="bottom-tip">最多仅可设置到未来2个月哦~</view>
  </view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import QueryPlanApi from '@/sheep/api/plan/queryplan';
import { onLoad } from '@dcloudio/uni-app';
// 顶部星期文案
const weekText = ['一', '二', '三', '四', '五', '六', '日']

// 排课接口信息
const resData = ref({})

// 最终渲染日历数据
const monthList = ref([])


const planId = ref(0)

onLoad((options) => {
  // 接收从详情页传过来的 planid
  planId.value = Number(options.planid) || 0
  console.log('收到计划ID:', planId.value, typeof planId.value)
})

// 格式化日期、后端数据转日历
const formatCalendar = () => {

  console.log('进入格式化,resData全部数据:', resData.value)
  // 没有data直接退出
  if (!resData.value?.data || !Array.isArray(resData.value.data)) {
    console.log('data不存在,终止格式化')
    monthList.value = []
    return
  }
  const now = new Date()
  const currentYear = now.getFullYear()
  const currentMonth = now.getMonth() + 1
  const today = now.getDate()

  const calcMonthArr = [currentMonth, currentMonth + 1, currentMonth + 2]

  const groupObj = {}

  resData.value.data.forEach(item => {
    // trainingDate 是 [年, 月, 日] 数组,直接解构
    // const [y, m, d] = item.trainingDate
    // const name = item.templates?.[0]?.templateName || ''

    // const key = `${y}-${m}`
    // if (!groupObj[key]) groupObj[key] = {}
    // groupObj[key][d] = name
    const [y, m, d] = item.trainingDate
    const template = item.templates?.[0]
    const name = template?.templateName || ''
    const DailyTemplateId = template?.id || null

    const key = `${y}-${m}`
    if (!groupObj[key]) groupObj[key] = {}
    groupObj[key][d] = {
      trainName: name,
      DailyTemplateId: DailyTemplateId
    }
  })

  const result = []
  calcMonthArr.forEach((month, idx) => {
    const year = currentYear + Math.floor((month - 1) / 12)
    const realMonth = month > 12 ? month - 12 : month
    const totalDay = new Date(year, realMonth, 0).getDate()
    let firstWeek = new Date(`${year}-${realMonth}-01`).getDay()
    firstWeek = firstWeek === 0 ? 7 : firstWeek
    let emptyCount = firstWeek - 1

    const dayList = []
    const startDay = idx === 0 ? today : 1

    for (let d = startDay; d <= totalDay; d++) {
      // const key = `${year}-${realMonth}`
      // const trainName = groupObj[key]?.[d] || ''

      // dayList.push({ day: d, trainName })
      const key = `${year}-${realMonth}`
      const trainInfo = groupObj[key]?.[d] || {}

      dayList.push({
        year: year,     // 年
        month: realMonth, // 月 
        day: d,
        trainName: trainInfo.trainName || '',
        // templateId: trainInfo.templateId || null
        DailyTemplateId: trainInfo.DailyTemplateId || null
      })
    }

    if (idx === 0) {
      const firstDayWeek = new Date(`${year}-${realMonth}-${startDay}`).getDay()
      const currentWeek = firstDayWeek === 0 ? 7 : firstDayWeek
      emptyCount = currentWeek - 1
    }

    result.push({
      month: realMonth,
      emptyCount,
      dayList
    })
  })

  monthList.value = result
}

// 返回上一页
const goBack = () => uni.navigateBack()

// 胶囊导航信息
const menuButtonInfo = ref({
  top: 44,
  height: 32
});


// 获取排课日历数据
const loadPlanCalendar = async () => {
  if (!planId.value) return
  try {
    const apiRes = await QueryPlanApi.getPlanArrangeCalendar(planId.value)
    console.log('接口返回的计划日历数据:', apiRes.value);
    resData.value = apiRes
    // 渲染日历
    formatCalendar()
  } catch (err) {
    console.error('日历接口报错', err)
  }
}

//查看模板详情
const openTemplateDatil = (DailyTemplateId, year, month, day) => {
  console.log('每日模板ID=', DailyTemplateId);
  console.log('完整日期=', year, month, day);
  const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
  if (!DailyTemplateId) return
  uni.navigateTo({
    url: `/pages4/pages/xunji/xunji-moban-xiangqing?id=${DailyTemplateId}&date=${dateStr}&isOffice=false&isMyPlan=true&isDailytemplateId=true`,
  });
};

onMounted(async () => {
  // #ifdef MP-WEIXIN
  try {
    const rect = uni.getMenuButtonBoundingClientRect();
    if (rect) {
      menuButtonInfo.value = {
        top: rect.top,
        height: rect.height
      };
    }
  } catch (e) { }
  // #endif
  // #ifndef MP-WEIXIN
  try {
    const systemInfo = uni.getSystemInfoSync();
    const statusBarHeight = systemInfo.statusBarHeight || 20;
    menuButtonInfo.value = {
      top: statusBarHeight,
      height: 44
    };
  } catch (e) { }
  // #endif
  // 加载排课信息
  loadPlanCalendar()
  // formatCalendar()
});

</script>

<style scoped lang="scss">
$bg-color: #121212;
$text-white: #fff;
$text-gray: #2f2f2f;
$train-yellow: #e9ee50;
$cell-h: 110rpx;

.paike-wrap {
  background: $bg-color;
  min-height: 100vh;
  padding-bottom: env(safe-area-inset-bottom);
  overflow: hidden;
}

.page-header {
  width: 100%;
  flex-shrink: 0;
  background-color: $bg-color;
}

.nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: $bg-color;
  padding-left: 16rpx;
  padding-right: 16rpx;
  box-sizing: content-box;
}

.nav-left {
  width: 60rpx;
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.nav-title {
  flex: 1;
  text-align: center;
  font-size: 36rpx;
  font-weight: bold;
  color: $text-white;
}

.nav-right {
  width: 60rpx;
  flex-shrink: 0;
}

.week-head {
  margin-top: 10rpx;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin: 20rpx 0;

  .week-cell {
    text-align: center;
    font-size: 25rpx;
    color: $text-white;
  }
}

.month-wrap {
  margin-bottom: 30rpx;
  background-color: #121212;

  .month-title {
    font-size: 25rpx;
    color: $text-white;
    padding: 15rpx 10rpx;
    text-align: center;
  }

  .date-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1rpx;
  }

  .date-cell {
    height: $cell-h;
    background: $bg-color;
    border-radius: 8rpx;
    padding: 8rpx;
    display: flex;
    flex-direction: column;
    justify-content: space-between;

    .day-num {
      font-size: 25rpx;
      color: $text-white;
      text-align: center;
      display: block;
      width: 100%;
    }

    .train-label-box {
      min-height: 56rpx;
      width: 100%;
    }

    .train-label {
      background: $train-yellow;
      color: #000;
      font-size: 22rpx;
      padding: 4rpx 3rpx;
      border-radius: 2rpx;
      line-height: 1.3;
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      height: 56rpx;
      text-align: center;

    }

    .empty-label {
      width: 100%;
      min-height: 56rpx;
      background: $text-gray;
      border-radius: 2rpx;
    }
  }

  .empty-cell {
    background: transparent !important;
  }
}

.bottom-tip {
  text-align: center;
  font-size: 30rpx;
  color: $text-white;
  margin-top: 60rpx;

  /* #ifdef H5 */
  margin-bottom: 20px;
  /* #endif */

}
</style>