<!--
 * @Author: wanglj wanglijie@dashoo.cn
 * @Date: 2025-03-24 16:28:47
 * @LastEditors: wanglj wanglijie@dashoo.cn
 * @LastEditTime: 2025-03-28 11:47:37
 * @FilePath: \labsop_h5\src\view\instr\components\appoint-dialog.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
  <div class="calendar-container">
    <header>
      <p>
        <strong><van-icon name="calendar-o" :size="16" />预约时间：</strong>
        <span v-if="state.selected.length === 0">请选择开始时间段</span>
        <span v-else-if="state.selected.length === 1">{{ formatDate(new Date(state.selected[0].startStamp), 'mm-dd HH:MM') }}~{{ formatDate(new Date(state.selected[0].endStamp), 'mm-dd HH:MM') }}</span>
        <span v-else-if="state.selected.length === 2">{{ formatDate(new Date(state.selected[0].startStamp), 'mm-dd HH:MM') }}~{{ formatDate(new Date(state.selected[1].endStamp), 'mm-dd HH:MM') }}</span>
      </p>
      <p>
        <strong><van-icon name="clock-o" :size="16" />预约时长：</strong>
        <span>{{ getAppointTime() }}</span>
      </p>
    </header>
    <div class="main">
      <template v-for="(item, index) in state.calendar">
        <h4 v-if="item.startTime == '00:00'">{{ formatDate(new Date(item.startStamp), 'YYYY-mm-dd/WWW') }}</h4>
        <div class="tag" :class="{ disabled: item.disabled, selected: item.selected }" @click="onTagClick(item, index)">
          {{ item.startTime }}-{{ item.endTime }}
        </div>
      </template>
    </div>
  </div>
  <van-action-bar placeholder>
    <van-action-bar-button class="w100" type="primary" text="提交" @click="onClickButton" />
  </van-action-bar>
</template>
<script lang="ts" setup>
  import { onMounted, reactive, ref } from 'vue'
  import { formatDate } from '/@/utils/formatTime'
  import { showNotify } from 'vant'
  import { useRoute, useRouter } from 'vue-router'
  import moment from 'moment'
  import to from 'await-to-js'
  import { useInstrApi } from '/@/api/instr'
  const route = useRoute()
  const router = useRouter()
  const instId = ref(0)
  const instApi = useInstrApi()
  const state = reactive({
    instInfo: {} as any,
    intervalTime: 30,
    furtherLimit: '',
    instrBusinessTime: '',
    begin_at: '00:00:00',
    ent_at: '23:50:00',
    currentWeekAppointList: [],
    selected: [],
    calendar: []
  })
  // 获取系统设置时间间隔
  const getTimeSplit = async () => {
    const [err, res]: ToResponse = await to(
      instApi.getSettingDetail({
        instId: Number(instId.value),
        code: 'InstCfgAppoint'
      })
    )
    if (err) return
    if (res.code == 200) {
      state.intervalTime = res.data?.config?.timeSplit
      state.begin_at = res.data?.config?.timeRange?.[0].start
      state.ent_at = res.data?.config?.timeRange?.[0].end
      appointTimeInfo()
    }
  }
  const appointTimeInfo = async () => {
    const currentDate = formatDate(new Date(), 'YYYY-mm-dd')
    const nextWeek = formatDate(new Date(new Date().getTime() + 604800000), 'YYYY-mm-dd')
    let params = {
      instId: instId.value,
      date: currentDate,
      dateType: 'week'
    }
    await Promise.all([
      instApi.getAppointInfo({ ...params }),    
      instApi.getAppointInfo({...params, date: nextWeek})
    ]).then(([now, next]) => {
      const { appoint, unavailable, furtherLimit } = now.data
      const { appoint: appointNext, unavailable: unavailableNext } = next.data
      let allDate = [...(appoint || []), ...(unavailable || []), ...(appointNext || []), ...(unavailableNext || [])].map((item) => ({
        ...item,
        start: item.startTime ? item.startTime : item.start,
        startStamp: new Date(item.startTime ? item.startTime : item.start).getTime(),
        end: item.endTime ? item.endTime : item.end,
        endStamp: new Date(item.endTime ? item.endTime : item.end).getTime(),
      }))
      state.currentWeekAppointList = allDate
      state.furtherLimit = furtherLimit ? nearFurtherLimit(furtherLimit, state.intervalTime) : ''
      // 设备的工作时间
      state.instrBusinessTime = `${state.begin_at}-${state.ent_at}`
      initCalendar()
    })
  }
  const nearFurtherLimit = (time, split) => {
    // 将目标时间转换为Moment对象
    const targetMoment = moment(time)

    // 计算距离目标时间最近的能够被时间间隔整除的时间
    const remainder = targetMoment.minute() % split
    const divisibleTime = targetMoment.clone().subtract(remainder, 'minutes')
    const nearestAvailableTime = divisibleTime.format('YYYY/MM/DD HH:mm') + ':00'
    return nearestAvailableTime
  }
  const initCalendar = () => {
    const split = state.intervalTime
    const now = new Date().getTime()
    const start = formatDate(new Date(now), 'YYYY-mm-dd 00:00:00')
    const end = formatDate(new Date(now + 1000 * 60 * 60 * 24 * 7), 'YYYY-mm-dd 23:59:59')
    let stamp = new Date(start).getTime()
    while (stamp <= new Date(end).getTime()) {
      const obj = {
        startStamp: stamp,
        endStamp: stamp + 1000 * split * 60,
        startTime: formatDate(new Date(stamp), 'HH:MM'),
        endTime: formatDate(new Date(stamp + 1000 * split * 60), 'HH:MM'),
        disabled: stamp < now,
        selected: false
      }
      // 禁用不可预约时间段和已预约时间段
      for(const item of state.currentWeekAppointList) {
        if(obj.endStamp <= item.endStamp) {
          obj.disabled = true
          continue
        }
      }
      // 最早预约时间
      if(state.furtherLimit && obj.startStamp >= new Date(state.furtherLimit).getTime()) {
        obj.disabled = true
      }
      state.calendar.push(obj)
      stamp += 1000 * split * 60
    }
  }
  const onTagClick = (item: any, idx: number) => {
    if (item.disabled) return
    if (item.selected && state.selected[0].startStamp === item.startStamp) {
      return
    }

    if (state.selected.length === 2) {
      state.selected = []
      for (const item of state.calendar) {
        item.selected = false
      }
    } else if (state.selected.length === 1) {
      // 验证选中时间段是否有占用的
      const selected = JSON.parse(JSON.stringify(state.selected))
      selected.push(item)
      selected.sort((a, b) => {
        return a.startStamp - b.startStamp
      })
      let flag = false
      for (const item of state.calendar) {
        if (item.startStamp >= selected[0].startStamp && item.endStamp <= selected[1].endStamp && item.disabled) {
          flag = true
          break
        }
      }
      if (flag) {
        showNotify({
          message: '选中时间段已被占用,请重新选择',
          type: 'warning'
        })
        return
      }
    }
    state.selected.push(item)
    item.selected = true
    state.selected.sort((a, b) => {
      return a.startStamp - b.startStamp
    })
    if (state.selected.length == 2) {
      for (const item of state.calendar) {
        if (item.startStamp >= state.selected[0].startStamp && item.endStamp <= state.selected[1].endStamp) {
          item.selected = true
        }
      }
    }
  }
  const getAppointTime = () => {
    let startDate: Date = new Date()
    let endDate: Date = new Date()
    if(state.selected.length === 1) {
      startDate = new Date(state.selected[0].startStamp)
      endDate = new Date(state.selected[0].endStamp)
    } else if(state.selected.length === 2) {
      startDate = new Date(state.selected[0].startStamp)
      endDate = new Date(state.selected[1].endStamp)
    } else {
      return '-'
    }
    // 计算两个日期之间的时间差（以毫秒为单位）
    const timeDifference = endDate.getTime() - startDate.getTime()
    // 计算天数
    const days = Math.floor(timeDifference / (1000 * 60 * 60 * 24))
    // 计算剩余的毫秒数
    const remainingMilliseconds = timeDifference % (1000 * 60 * 60 * 24)
    // 计算小时数
    const hours = Math.floor(remainingMilliseconds / (1000 * 60 * 60))
    // 计算剩余的毫秒数
    const remainingMillisecondsAfterHours = remainingMilliseconds % (1000 * 60 * 60)
    // 计算分钟数
    const minutes = Math.floor(remainingMillisecondsAfterHours / (1000 * 60))
    return `${days}天${hours}小时${minutes}分`
  }
  const onClickButton = () => {
    if(!state.selected.length) {
      showNotify({
        message: '请选择预约时间',
        type: 'warning'
      })
      return
    }
    let startTime = 0
    let endTime = 0
    if(state.selected.length === 1) {
      startTime = state.selected[0].startStamp
      endTime = state.selected[0].endStamp
    } else {
      startTime = state.selected[0].startStamp
      endTime = state.selected[1].endStamp
    }
    router.push({
      path: '/instr-appoint',
      query: {
        id: instId.value,
        startTime,
        endTime
      }
    })
  }
  onMounted(() => {
    instId.value = route.query.id ? +route.query.id : 0
    getTimeSplit()
  })
</script>
<style lang="scss" scoped>
  .calendar-container {
    flex: 1;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    header {
      padding: 10px;
      border-bottom: 1px solid #dcdfe6;
      p {
        padding: 4px;
        i {
          margin-right: 4px;
        }
      }
    }
    .main {
      flex: 1;
      overflow-y: auto;
      overflow-x: hidden;
      padding: 10px 6px;
      display: flex;
      flex-wrap: wrap;
      color: #323233;
      h4 {
        flex: 0 0 100%;
        margin: 4px 0 0 4px;
        height: 18px;
        line-height: 18px;
        display: flex;
        &::before {
          display: inline-block;
          content: '';
          width: 3px;
          height: 18px;
          background-color: #1c9bfd;
          margin-right: 4px;
          vertical-align: middle;
        }
      }
      .tag {
        font-size: 12px;
        text-align: center;
        flex: 0 0 calc(25% - 14px);
        padding: 4px;
        border: 1px solid #dcdfe6;
        border-radius: 4px;
        margin-left: 4px;
        margin-top: 4px;
        &.disabled {
          background-color: #dcdfe6;
        }
        &.selected {
          background-color: #1989fa;
          border-color: #1989fa;
          color: #fff;
        }
      }
    }
  }
</style>
