<template>
  <el-dialog
    :visible.sync="visibleProxy"
    :show-close="false"
    width="96%"
    :close-on-click-modal="false"
    custom-class="employee-schedule-dialog"
    append-to-body
  >
    <div class="dialog-inner">
      <div class="dialog-header">
        <div class="dialog-title">{{ selectedDay ? selectedDayLabel + ' · 排班详情' : '员工排班 · 预约一览' }}</div>
        <div class="header-actions">
          <span v-if="selectedDay" class="back-btn" @click="selectedDay = null"><i class="el-icon-arrow-left"></i> 返回周视图</span>
          <span class="dialog-close" @click="visibleProxy = false"><i class="el-icon-close"></i></span>
        </div>
      </div>

      <div class="schedule-toolbar">
        <div class="week-nav">
          <button class="nav-btn" @click="prevWeek"><i class="el-icon-arrow-left"></i></button>
          <span class="week-label">{{ weekLabel }}</span>
          <button class="nav-btn" @click="nextWeek"><i class="el-icon-arrow-right"></i></button>
        </div>
        <div class="day-pills" v-if="!selectedDay">
          <span
            v-for="d in weekDays"
            :key="d.date"
            :class="['day-pill', { 'day-pill--today': d.isToday }]"
            @click="selectedDay = d.date"
          >{{ d.weekday }} {{ d.dateStr }}</span>
        </div>
        <div class="schedule-legend">
          <span class="legend-item"><i class="legend-dot legend-dot--booked"></i>已预约</span>
          <span class="legend-item"><i class="legend-dot legend-dot--confirmed"></i>已确认</span>
          <span class="legend-item"><i class="legend-dot legend-dot--leave"></i>请假</span>
          <span class="legend-item"><i class="legend-dot legend-dot--vacation"></i>休假</span>
          <span class="legend-item"><i class="legend-dot legend-dot--rest"></i>休息</span>
          <span class="legend-item"><i class="legend-dot legend-dot--slot"></i>30分钟/格</span>
        </div>
      </div>

      <div class="schedule-wrap">
        <div class="schedule-table" :class="{ 'schedule-table--day': selectedDay }">
          <div class="schedule-header">
            <div class="schedule-cell schedule-cell--employee">
              <span>员工</span>
              <span v-if="selectedDay" class="header-time-label">时间</span>
            </div>
            <div v-for="d in displayDays" :key="d.date" class="schedule-cell schedule-cell--day">
              <div class="day-name">{{ d.weekday }}</div>
              <div class="day-date">{{ d.dateStr }}</div>
              <!-- 日视图：时间刻度 -->
              <div v-if="selectedDay" class="day-slots day-slots--time">
                <div v-for="i in 48" :key="i" class="slot-time" :class="{ 'slot-time--show': (i - 1) % 2 === 0 }">
                  {{ (i - 1) % 2 === 0 ? formatSlotTime(i - 1) : '' }}
                </div>
              </div>
            </div>
          </div>
          <div v-for="emp in employeeList" :key="emp.id" class="schedule-row">
            <div
              class="schedule-cell schedule-cell--employee schedule-employee"
              :class="{ 'schedule-employee--clickable': selectedDay }"
            >
              <span
                class="employee-name"
                :class="{ 'employee-name--clickable': selectedDay }"
                :title="selectedDay ? '点击可代入健康师添加预约' : ''"
                @click="selectedDay && handleEmployeeClick(emp)"
              >{{ emp.name }}</span>
              <span class="employee-role">{{ emp.role }}</span>
            </div>
            <div v-for="d in displayDays" :key="d.date" class="schedule-cell schedule-cell--day">
              <div class="day-cell-inner">
                <div class="day-meta">
                  <span v-if="getClockIn(emp.id, d.date)" class="clock-in"><i class="el-icon-time"></i> {{ getClockIn(emp.id, d.date) }}</span>
                  <span v-else class="clock-in clock-in--none">未打卡</span>
                  <span :class="['status-tag', 'status-tag--' + (getEmployeeDayStatus(emp.id, d.date).type || 'normal')]">
                    {{ getEmployeeDayStatus(emp.id, d.date).text }}
                  </span>
                </div>
                <div
                  v-if="isFullDayStatus(emp.id, d.date)"
                  :class="['day-slots', 'day-slots--leave', getEmployeeDayStatus(emp.id, d.date).type === 'vacation' ? 'day-slots--vacation' : '']"
                >
                  <div class="leave-cover">{{ getEmployeeDayStatus(emp.id, d.date).text }}</div>
                </div>
                <div v-else class="day-slots">
                  <div
                    v-for="i in 48"
                    :key="i"
                    :class="['slot', slotClass(emp.id, d.date, i - 1), { 'slot--clickable': selectedDay }, { 'slot--in-drag': isSlotInDragRange(emp.id, d.date, i - 1) }]"
                    :title="getSlotTooltip(emp.id, d.date, i - 1) + (slotClass(emp.id, d.date, i - 1).includes('resize') ? ' · 拖动边缘可调整时长' : '')"
                    @mousedown="handleSlotMouseDown($event, emp, d.date, i - 1)"
                    @mouseenter="selectedDay && handleSlotMouseEnter(emp.id, d.date, i - 1)"
                  ></div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 预约详情弹窗：风格与主弹窗统一 -->
    <el-dialog
      :visible.sync="detailDialogVisible"
      width="440px"
      append-to-body
      custom-class="schedule-detail-dialog"
      :show-close="false"
      :close-on-click-modal="false"
    >
      <div v-if="selectedBooking" class="booking-detail-inner">
        <div class="booking-detail-header">
          <div class="booking-detail-title">预约详情</div>
          <span class="booking-detail-close" @click="detailDialogVisible = false"><i class="el-icon-close"></i></span>
        </div>
        <div class="booking-detail-body">
          <div class="detail-row"><span class="label">会员姓名</span><span>{{ selectedBooking.customerName }}</span></div>
          <div class="detail-row"><span class="label">预约时间</span><span>{{ selectedBooking.timeRange }}</span></div>
          <div class="detail-row"><span class="label">预约项目</span><span>{{ selectedBooking.project || '—' }}</span></div>
          <div class="detail-row"><span class="label">状态</span><span :class="'status-' + (selectedBooking.status === '已确认' ? 'confirmed' : 'booked')">{{ selectedBooking.status }}</span></div>
          <div class="detail-row" v-if="selectedBooking.remark"><span class="label">备注</span><span>{{ selectedBooking.remark }}</span></div>
        </div>
        <div class="booking-detail-footer">
          <el-button size="small" @click="detailDialogVisible = false">关 闭</el-button>
          <el-button type="primary" size="small" @click="openEditBooking">编 辑</el-button>
        </div>
      </div>
    </el-dialog>

    <!-- 添加预约：复用新建预约弹窗，仅默认健康师、日期、时间 -->
    <BookingDialog
      :visible.sync="addBookingDialogVisible"
      :prefill="addBookingPrefill"
      :health-worker-options="healthWorkerOptionsFromEmployees"
    />
  </el-dialog>
</template>

<script>
import BookingDialog from '@/components/BookingDialog.vue'

export default {
  name: 'EmployeeScheduleDialog',
  components: { BookingDialog },
  props: {
    visible: { type: Boolean, default: false },
    openMode: { type: String, default: 'view' }
  },
  data() {
    return {
      weekStart: null,
      selectedDay: null,
      detailDialogVisible: false,
      addBookingDialogVisible: false,
      selectedBooking: null,
      addBookingPrefill: {},
      dragState: null,
      employeeList: [
        { id: 'E001', name: '董顺秀', role: '健康师' },
        { id: 'E002', name: '张丽', role: '健康师' },
        { id: 'E003', name: '贾琳', role: '健康师' },
        { id: 'E004', name: '刘恬恬', role: '健康师' }
      ],
      // 打卡数据：key = employeeId_date
      clockInData: {
        'E001_0': '09:05',
        'E001_1': '08:58',
        'E002_0': '09:12',
        'E002_2': '09:00',
        'E003_0': null,
        'E004_0': '10:20'
      },
      // 员工当日状态：key = employeeId_dayOffset, value = { type: 'normal'|'leave'|'vacation'|'rest', text, slotStart?, slotEnd? }
      // slotStart/slotEnd 为可选，表示半天请假/休假的时段（slot 索引 0-47）
      employeeDayStatus: {
        'E003_0': { type: 'leave', text: '事假' },
        'E002_1': { type: 'vacation', text: '年假' },
        'E004_1': { type: 'leave', text: '事假(半天)', slotStart: 18, slotEnd: 24 }
      },
      bookings: [
        { id: 'B1', employeeId: 'E001', dayOffset: 0, slotStart: 18, slotEnd: 20, customerName: '刘泽蓉', customerPhone: '159****8353', project: '美拉-面部', status: '已确认', remark: '' },
        { id: 'B2', employeeId: 'E001', dayOffset: 0, slotStart: 26, slotEnd: 30, customerName: '林晓薇', customerPhone: '138****8801', project: '逆龄胶原-眼部', status: '已预约', remark: '' },
        { id: 'B3', employeeId: 'E001', dayOffset: 0, slotStart: 34, slotEnd: 36, customerName: '陈美玲', customerPhone: '139****2233', project: '生命之波', status: '已确认', remark: '' },
        { id: 'B4', employeeId: 'E001', dayOffset: 1, slotStart: 18, slotEnd: 20, customerName: '张芳芳', status: '已预约', project: '面部护理' },
        { id: 'B5', employeeId: 'E001', dayOffset: 1, slotStart: 22, slotEnd: 24, customerName: '王晓燕', status: '已预约', project: '眼周护理' },
        { id: 'B6', employeeId: 'E002', dayOffset: 0, slotStart: 20, slotEnd: 22, customerName: '李明珠', status: '已确认', project: '精雕' },
        { id: 'B7', employeeId: 'E002', dayOffset: 0, slotStart: 28, slotEnd: 32, customerName: '周丽', status: '已预约', project: '微雕-面部' },
        { id: 'B8', employeeId: 'E002', dayOffset: 2, slotStart: 18, slotEnd: 22, customerName: '赵美华', status: '已确认', project: '逆龄胶原' },
        { id: 'B9', employeeId: 'E003', dayOffset: 0, slotStart: 18, slotEnd: 19, customerName: '罗建琼', status: '已确认', project: '美拉-面部' },
        { id: 'B10', employeeId: 'E003', dayOffset: 0, slotStart: 30, slotEnd: 34, customerName: '范佳佳', status: '已预约', project: 'CELL神经' },
        { id: 'B11', employeeId: 'E003', dayOffset: 0, slotStart: 34, slotEnd: 36, customerName: '黄仕碧', status: '已预约', project: '生命之波' },
        { id: 'B12', employeeId: 'E004', dayOffset: 0, slotStart: 28, slotEnd: 30, customerName: '王英', status: '已预约', project: '面部护理' },
        { id: 'B13', employeeId: 'E004', dayOffset: 3, slotStart: 20, slotEnd: 24, customerName: '沈丽', status: '已确认', project: '眼周护理' }
      ]
    }
  },
  computed: {
    visibleProxy: {
      get() { return this.visible },
      set(v) { this.$emit('update:visible', v) }
    },
    weekLabel() {
      if (!this.weekStart) return ''
      const start = this.weekStart
      const end = new Date(start)
      end.setDate(end.getDate() + 6)
      return `${start.getFullYear()}年${start.getMonth() + 1}月${start.getDate()}日 - ${end.getMonth() + 1}月${end.getDate()}日`
    },
    selectedDayLabel() {
      if (!this.selectedDay) return ''
      const d = new Date(this.selectedDay)
      const wd = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
      return `${this.selectedDay} ${wd[d.getDay()]}`
    },
    weekDays() {
      if (!this.weekStart) return []
      const today = new Date().toISOString().slice(0, 10)
      const days = []
      const wd = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
      for (let i = 0; i < 7; i++) {
        const d = new Date(this.weekStart)
        d.setDate(d.getDate() + i)
        const y = d.getFullYear()
        const m = String(d.getMonth() + 1).padStart(2, '0')
        const day = String(d.getDate()).padStart(2, '0')
        const dateStr = `${y}-${m}-${day}`
        days.push({
          date: dateStr,
          dateStr: `${m}/${day}`,
          weekday: wd[d.getDay()],
          dayOffset: i,
          isToday: dateStr === today
        })
      }
      return days
    },
    displayDays() {
      if (this.selectedDay) {
        const d = this.weekDays.find(x => x.date === this.selectedDay)
        return d ? [d] : []
      }
      return this.weekDays
    },
    healthWorkerOptionsFromEmployees() {
      return this.employeeList.map(e => ({ value: e.id, label: e.name }))
    },
    bookingsWithDate() {
      if (!this.weekStart) return []
      return this.bookings.map(b => {
        const d = new Date(this.weekStart)
        d.setDate(d.getDate() + b.dayOffset)
        const y = d.getFullYear()
        const m = String(d.getMonth() + 1).padStart(2, '0')
        const day = String(d.getDate()).padStart(2, '0')
        const timeStart = `${String(Math.floor(b.slotStart / 2)).padStart(2, '0')}:${(b.slotStart % 2) ? '30' : '00'}`
        const timeEnd = `${String(Math.floor(b.slotEnd / 2)).padStart(2, '0')}:${(b.slotEnd % 2) ? '30' : '00'}`
        return { ...b, date: `${y}-${m}-${day}`, timeRange: `${timeStart}-${timeEnd}` }
      })
    }
  },
  watch: {
    visible(v) {
      if (v && !this.weekStart) this.initWeek()
      if (v && this.openMode === 'set') {
        this.$nextTick(() => {
          this.gotoNextWeek()
          this.$store.commit('SET_SCHEDULE_DIALOG_MODE', 'view')
        })
      }
      if (!v) this.selectedDay = null
    }
  },
  mounted() {
    this.initWeek()
  },
  methods: {
    initWeek() {
      const now = new Date()
      const dow = now.getDay()
      const start = new Date(now)
      start.setDate(now.getDate() - dow)
      start.setHours(0, 0, 0, 0)
      this.weekStart = start
    },
    prevWeek() {
      const d = new Date(this.weekStart)
      d.setDate(d.getDate() - 7)
      this.weekStart = d
      this.selectedDay = null
    },
    nextWeek() {
      const d = new Date(this.weekStart)
      d.setDate(d.getDate() + 7)
      this.weekStart = d
      this.selectedDay = null
    },
    gotoNextWeek() {
      const now = new Date()
      const dow = now.getDay()
      const daysUntilNextMonday = dow === 0 ? 1 : 8 - dow
      const nextMonday = new Date(now)
      nextMonday.setDate(now.getDate() + daysUntilNextMonday)
      nextMonday.setHours(0, 0, 0, 0)
      this.weekStart = nextMonday
      this.selectedDay = null
    },
    formatSlotTime(slotIndex) {
      const h = Math.floor(slotIndex / 2)
      const m = (slotIndex % 2) * 30
      return `${h}:${m === 0 ? '00' : '30'}`
    },
    handleEmployeeClick(emp) {
      if (!this.selectedDay) return
      this.addBookingPrefill = {
        yyjks: emp.id,
        yyrq: new Date(this.selectedDay + 'T12:00:00')
      }
      this.addBookingDialogVisible = true
    },
    getClockIn(empId, date) {
      const d = this.weekDays.find(x => x.date === date)
      if (!d) return null
      const key = `${empId}_${d.dayOffset}`
      return this.clockInData[key] || null
    },
    getEmployeeDayStatus(empId, date) {
      const d = this.weekDays.find(x => x.date === date)
      if (!d) return { type: 'normal', text: '正常' }
      const key = `${empId}_${d.dayOffset}`
      return this.employeeDayStatus[key] || { type: 'normal', text: '正常' }
    },
    isFullDayStatus(empId, date) {
      const s = this.getEmployeeDayStatus(empId, date)
      if (s.type !== 'leave' && s.type !== 'vacation') return false
      return s.slotStart == null && s.slotEnd == null
    },
    isSlotInLeaveRange(empId, date, slotIndex) {
      const s = this.getEmployeeDayStatus(empId, date)
      if (s.type !== 'leave' && s.type !== 'vacation') return false
      if (s.slotStart == null || s.slotEnd == null) return false
      return slotIndex >= s.slotStart && slotIndex < s.slotEnd
    },
    isSlotInDragRange(empId, date, slotIndex) {
      if (!this.dragState || this.dragState.employeeId !== empId) return false
      const d = this.weekDays.find(x => x.date === date)
      if (!d || this.dragState.dayOffset !== d.dayOffset) return false
      const [lo, hi] = this.dragState.startSlot <= this.dragState.endSlot
        ? [this.dragState.startSlot, this.dragState.endSlot]
        : [this.dragState.endSlot, this.dragState.startSlot]
      return slotIndex >= lo && slotIndex <= hi
    },
    slotClass(empId, date, slotIndex) {
      const b = this.bookingsWithDate.find(x =>
        x.employeeId === empId &&
        x.date === date &&
        slotIndex >= x.slotStart &&
        slotIndex < x.slotEnd
      )
      if (b) {
        let c = b.status === '已确认' ? 'slot--confirmed' : 'slot--booked'
        if (slotIndex === b.slotStart) c += ' slot--resize-start'
        if (slotIndex === b.slotEnd - 1) c += ' slot--resize-end'
        return c
      }
      if (this.isSlotInLeaveRange(empId, date, slotIndex)) return 'slot--leave'
      return ''
    },
    getSlotTooltip(empId, date, slotIndex) {
      const b = this.bookingsWithDate.find(x =>
        x.employeeId === empId &&
        x.date === date &&
        slotIndex >= x.slotStart &&
        slotIndex < x.slotEnd
      )
      if (b) {
        return `${b.timeRange} ${b.customerName}（${b.status}）${b.project ? ' · ' + b.project : ''}`
      }
      const h = Math.floor(slotIndex / 2)
      const m = (slotIndex % 2) * 30
      return `${h}:${m === 0 ? '00' : '30'} 空闲 · 点击可添加预约`
    },
    getDayTooltip(empId, date) {
      const list = this.bookingsWithDate.filter(x => x.employeeId === empId && x.date === date)
      if (list.length === 0) return '当日无预约 · 点击日期查看详情'
      return list.map(x => `${x.customerName} ${x.timeRange}`).join('\n') + '\n点击日期查看详情'
    },
    openEditBooking() {
      if (!this.selectedBooking) return
      const b = this.selectedBooking
      const [startStr] = (b.timeRange || '').split('-')
      this.addBookingPrefill = {
        yyjks: b.employeeId,
        yyrq: new Date(b.date + 'T12:00:00'),
        yysj: startStr ? startStr.trim() : '',
        yysjEnd: (b.timeRange || '').split('-')[1]?.trim() || '',
        editBookingId: b.id,
        gkxm: b.customerName,
        yytyxm: b.project
      }
      this.detailDialogVisible = false
      this.addBookingDialogVisible = true
    },
    handleSlotMouseDown(e, emp, date, slotIndex) {
      const b = this.bookingsWithDate.find(x =>
        x.employeeId === emp.id &&
        x.date === date &&
        slotIndex >= x.slotStart &&
        slotIndex < x.slotEnd
      )
      // 周视图下允许点击块直接查看详情，不支持拖动修改/新建
      if (!this.selectedDay) {
        if (b) {
          this.selectedBooking = b
          this.detailDialogVisible = true
        }
        return
      }
      if (b) {
        const rect = e.currentTarget.getBoundingClientRect()
        const x = e.clientX - rect.left
        const w = rect.width
        if (w > 12 && x < w / 3) {
          const bk = this.bookings.find(x => x.id === b.id)
          const originalStart = bk ? bk.slotStart : b.slotStart
          const originalEnd = bk ? bk.slotEnd : b.slotEnd
          this.dragState = { type: 'resize', bookingId: b.id, edge: 'start', date, employeeId: emp.id }
          const onMove = (ev) => {
            const slotEl = document.elementFromPoint(ev.clientX, ev.clientY)?.closest('.slot')
            if (!slotEl) return
            const row = slotEl.closest('.schedule-row')
            const empName = row?.querySelector('.employee-name')?.textContent
            const empObj = this.employeeList.find(e => e.name === empName)
            if (!empObj || empObj.id !== this.dragState.employeeId) return
            const idx = Array.from(slotEl.parentElement?.children || []).indexOf(slotEl)
            if (idx >= 0 && idx < 48) {
              const bk2 = this.bookings.find(x => x.id === this.dragState.bookingId)
              if (bk2) {
                const newStart = Math.min(idx, bk2.slotEnd - 1)
                if (newStart !== bk2.slotStart) {
                  this.$set(bk2, 'slotStart', newStart)
                }
              }
            }
          }
          const onUp = () => {
            document.removeEventListener('mousemove', onMove)
            document.removeEventListener('mouseup', onUp)
            const bk3 = this.bookings.find(x => x.id === this.dragState.bookingId)
            this.dragState = null
            if (!bk3) return
            const newStart = bk3.slotStart
            if (newStart === originalStart) return
            const timeStart = `${String(Math.floor(newStart / 2)).padStart(2, '0')}:${(newStart % 2) ? '30' : '00'}`
            const timeEnd = `${String(Math.floor(bk3.slotEnd / 2)).padStart(2, '0')}:${(bk3.slotEnd % 2) ? '30' : '00'}`
            this.$confirm(`确定将预约时间调整为 ${timeStart} - ${timeEnd} 吗？`, '确认调整', {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              type: 'warning'
            }).then(() => {
              // 用户确认，保持当前已修改的值
            }).catch(() => {
              this.$set(bk3, 'slotStart', originalStart)
            })
          }
          document.addEventListener('mousemove', onMove)
          document.addEventListener('mouseup', onUp)
        } else if (w > 12 && x > (2 * w) / 3) {
          const bk = this.bookings.find(x => x.id === b.id)
          const originalStart = bk ? bk.slotStart : b.slotStart
          const originalEnd = bk ? bk.slotEnd : b.slotEnd
          this.dragState = { type: 'resize', bookingId: b.id, edge: 'end', date, employeeId: emp.id }
          const onMove = (ev) => {
            const slotEl = document.elementFromPoint(ev.clientX, ev.clientY)?.closest('.slot')
            if (!slotEl) return
            const row = slotEl.closest('.schedule-row')
            const empName = row?.querySelector('.employee-name')?.textContent
            const empObj = this.employeeList.find(e => e.name === empName)
            if (!empObj || empObj.id !== this.dragState.employeeId) return
            const idx = Array.from(slotEl.parentElement?.children || []).indexOf(slotEl)
            if (idx >= 0 && idx < 48) {
              const bk2 = this.bookings.find(x => x.id === this.dragState.bookingId)
              if (bk2) {
                const newEnd = Math.max(idx + 1, bk2.slotStart + 1)
                if (newEnd !== bk2.slotEnd) {
                  this.$set(bk2, 'slotEnd', newEnd)
                }
              }
            }
          }
          const onUp = () => {
            document.removeEventListener('mousemove', onMove)
            document.removeEventListener('mouseup', onUp)
            const bk3 = this.bookings.find(x => x.id === this.dragState.bookingId)
            this.dragState = null
            if (!bk3) return
            const newEnd = bk3.slotEnd
            if (newEnd === originalEnd) return
            const timeStart = `${String(Math.floor(bk3.slotStart / 2)).padStart(2, '0')}:${(bk3.slotStart % 2) ? '30' : '00'}`
            const timeEnd = `${String(Math.floor(newEnd / 2)).padStart(2, '0')}:${(newEnd % 2) ? '30' : '00'}`
            this.$confirm(`确定将预约时间调整为 ${timeStart} - ${timeEnd} 吗？`, '确认调整', {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              type: 'warning'
            }).then(() => {
              // 用户确认，保持当前已修改的值
            }).catch(() => {
              this.$set(bk3, 'slotEnd', originalEnd)
            })
          }
          document.addEventListener('mousemove', onMove)
          document.addEventListener('mouseup', onUp)
        } else {
          this.selectedBooking = b
          this.detailDialogVisible = true
        }
        return
      }
      const d = this.weekDays.find(x => x.date === date)
      if (!d) return
      if (this.isSlotInLeaveRange(emp.id, date, slotIndex)) return
      this.dragState = {
        type: 'select',
        employeeId: emp.id,
        employee: emp,
        dayOffset: d.dayOffset,
        date,
        startSlot: slotIndex,
        endSlot: slotIndex
      }
      const onUp = () => {
        document.removeEventListener('mouseup', onUp)
        if (!this.dragState) return
        const [s, e2] = this.dragState.startSlot <= this.dragState.endSlot
          ? [this.dragState.startSlot, this.dragState.endSlot]
          : [this.dragState.endSlot, this.dragState.startSlot]
        const timeStart = `${String(Math.floor(s / 2)).padStart(2, '0')}:${(s % 2) ? '30' : '00'}`
        const timeEnd = `${String(Math.floor((e2 + 1) / 2)).padStart(2, '0')}:${((e2 + 1) % 2) ? '30' : '00'}`
        this.addBookingPrefill = {
          yyjks: this.dragState.employeeId,
          yyrq: new Date(this.dragState.date + 'T12:00:00'),
          yysj: timeStart,
          yysjEnd: timeEnd
        }
        this.dragState = null
        this.$nextTick(() => {
          this.addBookingDialogVisible = true
        })
      }
      document.addEventListener('mouseup', onUp)
    },
    handleSlotMouseEnter(empId, date, slotIndex) {
      if (!this.dragState || this.dragState.type !== 'select' || this.dragState.employeeId !== empId) return
      const d = this.weekDays.find(x => x.date === date)
      if (!d || this.dragState.dayOffset !== d.dayOffset) return
      this.dragState.endSlot = slotIndex
    },
  }
}
</script>

<style lang="scss" scoped>
::v-deep .employee-schedule-dialog {
  max-width: 1400px;
  margin-top: 2vh !important;
  border-radius: 20px;
  padding: 0;
  background: radial-gradient(circle at 0 0, rgba(255,255,255,0.96) 0, rgba(248,250,252,0.98) 40%, rgba(241,245,249,0.98) 100%);
  box-shadow: 0 24px 48px rgba(15,23,42,0.18), 0 0 0 1px rgba(255,255,255,0.9);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
}

::v-deep .el-dialog__header { display: none; }
::v-deep .el-dialog__body { padding: 0; }

.dialog-inner {
  display: flex;
  flex-direction: column;
  max-height: 90vh;
}

.dialog-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 18px 22px 0;
  padding: 10px 14px;
  border-radius: 14px;
  background: rgba(219,234,254,0.96);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.back-btn {
  font-size: 13px;
  color: #6366f1;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
  &:hover { text-decoration: underline; }
}

.dialog-title {
  font-size: 17px;
  font-weight: 600;
  color: #0f172a;
}

.dialog-close {
  cursor: pointer;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: #64748b;
  transition: all 0.15s;
  &:hover { background: rgba(0,0,0,0.06); color: #0f172a; }
}

.schedule-toolbar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 14px 22px;
}

.week-nav {
  display: flex;
  align-items: center;
  gap: 12px;
}

.nav-btn {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid #e2e8f0;
  background: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #64748b;
  transition: all 0.2s;
  &:hover {
    background: rgba(99, 102, 241, 0.08);
    border-color: rgba(99, 102, 241, 0.25);
    color: #4f46e5;
  }
}

.week-label {
  font-size: 14px;
  font-weight: 600;
  color: #1e293b;
  min-width: 260px;
  text-align: center;
}

.day-pills {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.day-pill {
  padding: 6px 12px;
  border-radius: 8px;
  font-size: 12px;
  color: #64748b;
  background: #f1f5f9;
  cursor: pointer;
  transition: all 0.2s;
  &:hover {
    background: rgba(99, 102, 241, 0.1);
    color: #4f46e5;
  }
  &--today {
    background: rgba(99, 102, 241, 0.15);
    color: #4f46e5;
    font-weight: 600;
  }
}

.schedule-legend {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 12px;
  color: #64748b;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.legend-dot {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  display: inline-block;
}

.legend-dot--booked { background: #3b82f6; }
.legend-dot--confirmed { background: #22c55e; }
.legend-dot--leave { background: #f97316; }
.legend-dot--vacation { background: #8b5cf6; }
.legend-dot--rest { background: #94a3b8; }
.legend-dot--slot { background: #e2e8f0; }

.schedule-wrap {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 0 22px 22px;
}

.schedule-table {
  display: grid;
  grid-template-columns: 120px repeat(7, 1fr);
  min-width: 900px;
  border: 1px solid #e2e8f0;
  border-radius: 12px;
  overflow: hidden;
  background: #fff;

  &--day {
    grid-template-columns: 180px 1fr;
  }
}

.schedule-header {
  display: contents;
}

.schedule-row {
  display: contents;
}

.schedule-cell {
  padding: 10px 8px;
  border-bottom: 1px solid #f1f5f9;
  border-right: 1px solid #f1f5f9;
}

.schedule-cell--employee {
  position: sticky;
  left: 0;
  z-index: 2;
  background: #f8fafc;
  font-weight: 500;
}

.schedule-cell--day {
  min-width: 0;
}

.day-cell-inner {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.day-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 11px;
}

.schedule-header .schedule-cell--employee {
  background: #f1f5f9;
  font-size: 13px;
  font-weight: 600;
  color: #64748b;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.header-time-label {
  font-size: 11px;
  font-weight: 500;
  color: #94a3b8;
}

.schedule-header .schedule-cell--day {
  text-align: center;
  padding: 8px;
}

.day-name { font-size: 12px; color: #94a3b8; }
.day-date { font-size: 13px; font-weight: 600; color: #374151; margin-top: 2px; }

/* 日视图时间刻度 */
.day-slots--time {
  min-height: 18px;
  margin-top: 6px;
}

.slot-time {
  font-size: 9px;
  color: #94a3b8;
  display: flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  overflow: hidden;
  min-width: 0;
  &.slot-time--show {
    color: #64748b;
    font-weight: 500;
  }
}

.employee-name--clickable {
  cursor: pointer;
  padding: 2px 4px;
  margin: -2px -4px;
  border-radius: 4px;
  transition: background 0.15s;
  &:hover {
    background: rgba(99, 102, 241, 0.12);
    color: #4f46e5;
  }
}

.schedule-employee {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.employee-name { font-size: 14px; color: #111827; }
.employee-role { font-size: 11px; color: #94a3b8; }

.clock-in {
  color: #22c55e;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  &--none { color: #94a3b8; }
}

.status-tag {
  font-size: 10px;
  padding: 2px 6px;
  border-radius: 4px;
  display: inline-block;
  &--normal { background: #f1f5f9; color: #64748b; }
  &--leave { background: rgba(249, 115, 22, 0.15); color: #ea580c; }
  &--vacation { background: rgba(139, 92, 246, 0.15); color: #7c3aed; }
  &--rest { background: rgba(148, 163, 184, 0.2); color: #64748b; }
}

.day-slots {
  display: grid;
  grid-template-columns: repeat(48, 1fr);
  gap: 0;
  min-height: 24px;

  &--leave {
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(249, 115, 22, 0.08);
  }
  &--vacation {
    background: rgba(139, 92, 246, 0.08);
    .leave-cover { color: #7c3aed; }
  }
}

.leave-cover {
  font-size: 12px;
  color: #ea580c;
  font-weight: 500;
}

.slot {
  min-height: 20px;
  background: #f8fafc;

  &--clickable {
    cursor: pointer;
    &:hover { background: #e2e8f0; }
  }
}

.slot--booked {
  background: rgba(59, 130, 246, 0.5);
  &:hover { background: rgba(59, 130, 246, 0.7); }
  &.slot--resize-start.slot--resize-end { border-radius: 2px; }
  &.slot--resize-start:not(.slot--resize-end) { border-radius: 2px 0 0 2px; }
  &.slot--resize-end:not(.slot--resize-start) { border-radius: 0 2px 2px 0; }
  &:not(.slot--resize-start):not(.slot--resize-end) { border-radius: 0; }
}

.slot--confirmed {
  background: rgba(34, 197, 94, 0.5);
  &:hover { background: rgba(34, 197, 94, 0.7); }
  &.slot--resize-start.slot--resize-end { border-radius: 2px; }
  &.slot--resize-start:not(.slot--resize-end) { border-radius: 2px 0 0 2px; }
  &.slot--resize-end:not(.slot--resize-start) { border-radius: 0 2px 2px 0; }
  &:not(.slot--resize-start):not(.slot--resize-end) { border-radius: 0; }
}

.slot--leave {
  background: rgba(249, 115, 22, 0.35);
}

.slot--in-drag {
  background: rgba(99, 102, 241, 0.35);
}

.slot--resize-start { cursor: w-resize; }
.slot--resize-end { cursor: e-resize; }

/* 预约详情弹窗 - 与主弹窗风格统一 */
::v-deep .schedule-detail-dialog {
  border-radius: 20px;
  padding: 0;
  background: radial-gradient(circle at 0 0, rgba(255,255,255,0.96) 0, rgba(248,250,252,0.98) 40%, rgba(241,245,249,0.98) 100%);
  box-shadow: 0 24px 48px rgba(15,23,42,0.18), 0 0 0 1px rgba(255,255,255,0.9);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
}

::v-deep .schedule-detail-dialog .el-dialog__header { display: none; }
::v-deep .schedule-detail-dialog .el-dialog__body {
  padding: 22px;
}

.booking-detail-inner {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.booking-detail-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0 0 16px;
  padding: 12px 16px;
  border-radius: 14px;
  background: rgba(219,234,254,0.96);
}

.booking-detail-title { font-size: 17px; font-weight: 600; color: #0f172a; }

.booking-detail-close {
  cursor: pointer;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: #64748b;
  transition: all 0.15s;
  &:hover { background: rgba(0,0,0,0.06); color: #0f172a; }
}

.booking-detail-body {
  padding: 4px 0 16px;
}

.detail-row {
  display: flex;
  padding: 10px 0;
  border-bottom: 1px solid #f1f5f9;
  font-size: 14px;
  .label { width: 90px; color: #64748b; flex-shrink: 0; }
  .status-confirmed { color: #22c55e; font-weight: 600; }
  .status-booked { color: #3b82f6; font-weight: 600; }
}

.booking-detail-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 16px 0 0;
  border-top: 1px solid #f1f5f9;
}

::v-deep .schedule-detail-dialog .el-button--primary { border-radius: 999px; }
::v-deep .schedule-detail-dialog .el-button--default { border-radius: 999px; }
</style>
