<template>
  <div class="ticket-management-container">
    <!-- 顶部搜索区域 -->
    <div id="topSearchArea" class="top-search-area">
      <!-- 搜索标签行 -->
      <div class="search-labels">
        <div class="search-label">号源日期</div>
        <div class="search-label">状态</div>
        <div class="search-label">患者姓名</div>
        <div class="search-label">就诊卡号</div>
        <div class="search-label">手机号</div>
        <div class="search-label"></div> <!-- 为查询按钮预留空间 -->
      </div>
      
      <!-- 搜索输入行 -->
      <div class="search-inputs">
        <!-- 移动端汉堡菜单按钮 -->
        <div class="hamburger-menu" @click="toggleSidebar" v-if="isMobile">
          <i class="el-icon-menu"></i>
        </div>
        <div id="datePicker" class="date-picker">
          <el-date-picker
            v-model="selectedDate"
            type="date"
            placeholder="选择日期"
            format="YYYY/MM/DD"
            value-format="YYYY-MM-DD"
            :shortcuts="dateShortcuts"
            class="date-picker"
            @change="onDateChange"
          />
        </div>
        <div id="statusFilter" class="status-filter">
          <select id="status-select" class="search-select" v-model="selectedStatus" @change="onSearch">
            <option value="all">全部</option>
            <option value="unbooked">未预约</option>
            <option value="booked">已预约</option>
            <option value="checked">已取号</option>
            <option value="cancelled">已停诊</option>
            <option value="returned">已退号</option>
          </select>
        </div>
        <div id="patientSearch" class="patient-search">
          <input id="patient-name-input" class="search-input" placeholder="姓名" v-model="patientName">
        </div>
        <div id="cardSearch" class="card-search">
          <input id="patient-card-input" class="search-input" placeholder="就诊卡号" v-model="patientCard">
        </div>
        <div id="phoneSearch" class="phone-search">
          <input id="patient-phone-input" class="search-input" placeholder="手机号" v-model="patientPhone">
        </div>
        <div class="search-button">
          <button id="search-button" class="search-btn" @click="onSearch" :disabled="isLoading">
            <span v-if="isLoading" class="loading-text">搜索中...</span>
            <span v-else>查询</span>
          </button>
        </div>
      </div>
    </div>

    <!-- 主要内容区域 -->
    <div id="mainContent" class="main-content">
      <!-- 左侧筛选区域 -->
      <div id="leftSidebar" class="left-sidebar" :class="{ 'sidebar-hidden': isMobile && !showSidebar, 'sidebar-mobile': isMobile }">
        <!-- 科室列表 -->
        <div class="section">
          <h3 class="section-title">科室列表</h3>
          <select id="department-list" class="search-select" v-model="selectedDepartment" @change="onDepartmentChange">
            <option value="all">全部科室</option>
            <option v-for="department in departments" :key="department.value" :value="department.value">
              {{ department.label }}
            </option>
          </select>
        </div>

        <!-- 号源类型 -->
        <div class="section">
          <h3 class="section-title">号源类型</h3>
          <div class="radio-group">
            <label>
              <input type="radio" name="type" value="general" v-model="selectedType" @change="onTypeChange">
              <span>普通号</span>
            </label>
            <label>
              <input type="radio" name="type" value="expert" v-model="selectedType" @change="onTypeChange">
              <span>专家号</span>
            </label>
          </div>
        </div>

        <!-- 医生号源列表 -->
        <div class="section">
          <h3 class="section-title">医生号源列表</h3>
          <input id="doctor-search" class="search-input" placeholder="搜索医生姓名" v-model="searchQuery" @input="onDoctorSearch">
          <div class="doctor-list">
            <div class="doctor-item" v-for="doctor in filteredDoctors" :key="doctor.id" :class="{ selected: selectedDoctorId === doctor.id }" @click="selectDoctor(doctor.id)">
              <div class="doctor-name">{{ doctor.name }} <span class="doctor-available">余号：{{ doctor.available }}</span></div>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧号源卡片区域 -->
      <div class="right-content" :class="{ 'right-content-full': isMobile && !showSidebar }">
        <!-- 使用网格布局的号源卡片列表 -->
        <div class="ticket-grid" v-if="filteredTickets.length > 0">
          <div v-for="(item, index) in filteredTickets" :key="item.slot_id" class="ticket-card" @dblclick="handleDoubleClick(item)" @contextmenu.prevent="handleRightClick($event, item)">
            <!-- 序号放在最右侧 -->
            <div class="ticket-index">{{ item.seqNo != null ? item.seqNo : index + 1 }}</div>
            <!-- 1.时间 -->
            <div class="ticket-id-time">{{ item.dateTime }}</div>
            <!-- 2. 状态标签 -->
            <div class="ticket-status" :class="getStatusClass(item.status)">
              <span class="status-dot"></span>
              {{ item.status }}
            </div>
            <!-- 3. 医生姓名（截断显示，悬停展示完整信息） -->
            <div class="ticket-doctor" :title="item.doctor">{{ item.doctor }}</div>
            <!-- 4. 科室名称 -->
            <div class="ticket-department" :title="item.department || '未知科室'">
              科室：{{ item.department || '未知科室' }}
            </div>
            <!-- 5. 挂号费 -->
            <div class="ticket-fee">挂号费：{{ item.fee }}元</div>
            <!-- 6. 号源类型 -->
            <div class="ticket-type">{{ item.ticketType === 'general' ? '普通' : '专家' }}</div>
            <!-- 7. 已预约患者信息 -->
            <div v-if="(item.status === '已预约' || item.status === '已取号') && item.patientName" class="ticket-patient">
              {{ item.patientName }}({{ item.patientId }},{{ getGenderText(item.gender || item.patientGender) }})
            </div>
            <div class="ticket-actions">
              <button class="action-button book-button" @click="openPatientSelectModal(item.slot_id)" :disabled="item.status !== '未预约'" :class="{ 'disabled': item.status !== '未预约' }">
                <i class="el-icon-tickets"></i>
                预约
              </button>
            </div>
          </div>
        </div>
        <div class="pagination-container" v-if="totalTickets > 0">
          <el-pagination
            background
            layout="total, sizes, prev, pager, next, jumper"
            :total="totalTickets"
            :current-page="currentPage"
            :page-size="pageSize"
            :page-sizes="[15, 30, 50, 100]"
            @current-change="handlePageChange"
            @size-change="handlePageSizeChange"
          />
        </div>
        <div v-if="filteredTickets.length === 0" class="empty-state">
          <div class="empty-text">暂无号源数据</div>
        </div>
      </div>
    </div>

    <!-- 患者选择弹窗 -->
    <div id="patient-select-modal" class="modal" v-if="showPatientModal">
      <div class="modal-content">
        <div class="modal-header">
          <h3>选择患者</h3>
          <button class="close-btn" @click="closePatientSelectModal">&times;</button>
        </div>
        <div class="modal-body">
          <div class="patient-search-toolbar">
            <input
              id="patient-keyword"
              class="search-input patient-keyword-input"
              placeholder="姓名/就诊卡号/手机号/证件号回车查询"
              v-model.trim="patientKeyword"
              @keyup.enter="searchPatients"
            >
            <button id="patient-search-btn" class="search-btn" @click="searchPatients">查询</button>
            <button id="patient-reset-btn" class="reset-btn" @click="resetPatientSearch">重置</button>
          </div>
          <div class="patient-table-container">
            <table id="patient-table" class="patient-table" v-if="patients.length > 0">
              <thead>
                <tr>
                  <th>序号</th>
                  <th>患者姓名</th>
                  <th>就诊卡号</th>
                  <th>性别</th>
                  <th>身份证号</th>
                  <th>手机号</th>
                  <th>操作</th>
                </tr>
              </thead>
              <tbody>
                <tr
                  v-for="(patient, index) in patients"
                  :key="patient._rowKey"
                  :class="{ selected: selectedPatientId === patient._rowKey }"
                  @click="selectPatient(patient._rowKey)"
                >
                  <td>{{ index + 1 }}</td>
                  <td>{{ patient.name }}</td>
                  <td>{{ patient.identifierNo || patient.medicalCard || patient.id }}</td>
                  <td>{{ patient.identifierNo }}</td>
                  <td>{{ getGenderText(patient.genderEnum_enumText || patient.genderEnum || patient.gender || patient.sex) }}</td>
                  <td>{{ patient.idCard }}</td>
                  <td>{{ patient.phone }}</td>
                  <td>
                    <button class="select-btn" @click.stop="selectPatient(patient._rowKey)" :disabled="!patient._rowKey">选择</button>
                  </td>
                </tr>
              </tbody>
            </table>
            
            <!-- 无搜索结果提示 -->
            <div v-else-if="hasSearchCriteria && !isLoading" class="no-results">
              未找到符合条件的患者，请检查搜索条件
            </div>
          </div>
        </div>
        <div class="modal-footer">
          <button class="confirm-btn" @click="confirmPatientSelection">确认</button>
          <button class="cancel-btn" @click="closePatientSelectModal">取消</button>
        </div>
      </div>
    </div>
    <!-- 右键菜单 -->
    <div
      v-if="contextMenuVisible"
      class="context-menu"
      :style="{
        left: contextMenuPosition.x + 'px',
        top: contextMenuPosition.y + 'px'
      }"
      @click.stop
      @contextmenu.prevent
    >
      <div v-if="selectedTicketForCancel && selectedTicketForCancel.status === '已预约'" class="menu-item" @click="confirmCancelAppointment">
          取消预约
        </div>
    </div>

    <!-- 点击页面其他地方关闭右键菜单 -->
    <div
      v-if="contextMenuVisible"
      class="context-menu-overlay"
      @click="closeContextMenu"
      @contextmenu.prevent
    ></div>
  </div>
</template>

<script>
import { listTicket, listDoctorSummary, bookTicket, cancelTicket } from '@/api/appoinmentmanage/ticket';
import { getPatientList } from '@/api/cardRenewal/api';
import { listRegisterOrganizations } from '@/api/appoinmentmanage/dept';
import { ElDatePicker, ElPagination, ElMessageBox, ElMessage } from 'element-plus';
import useUserStore from '@/store/modules/user';

const STATUS_CLASS_MAP = {
  '未预约': 'status-unbooked',
  '已预约': 'status-booked',
  '已取号': 'status-checked',
  '已退号': 'status-returned',
  '已停诊': 'status-cancelled',
  '已取消': 'status-cancelled'
};

export default {
  name: 'OutpatientAppointment',
  components: {
    ElDatePicker,
    ElPagination
  },
  data() {
    return {
      selectedDate: new Date().toISOString().split('T')[0],
      selectedStatus: 'unbooked',
      selectedDepartment: 'all',
      selectedType: 'general', // 普通号默认选中
      selectedDoctorId: null,
      showPatientModal: false,
      selectedPatientId: null,
      selectedPatient: null,
      currentTicket: null,
      patientName: '',
      patientCard: '',
      patientPhone: '',
      isLoading: false,
      // 移动端相关变量
      isMobile: false,
      showSidebar: false,
      // 分页相关属性
      currentPage: 1,
      pageSize: 15,
      totalTickets: 0,
      // 右键菜单相关
      contextMenuVisible: false,
      contextMenuPosition: { x: 0, y: 0 },
      selectedTicketForCancel: null,
      departments: [
        { value: 'all', label: '全部科室' }
      ],
      doctors: [],
      allTickets: [], // 存储所有原始号源数据
      tickets: [], // 从API获取的真实号源数据
      patients: [], // 从API获取的真实患者数据
      searchQuery: '',
      patientKeyword: '',
      dateShortcuts: [
        { text: '今天', value: new Date() },
        { text: '明天', value: () => { const date = new Date(); date.setDate(date.getDate() + 1); return date; } },
        { text: '本周', value: () => { const date = new Date(); const day = date.getDay() || 7; date.setDate(date.getDate() - day + 1); return date; } },
        { text: '下周', value: () => { const date = new Date(); const day = date.getDay() || 7; date.setDate(date.getDate() - day + 8); return date; } },
        { text: '本月', value: () => { const date = new Date(); date.setDate(1); return date; } },
        { text: '下月', value: () => { const date = new Date(); date.setMonth(date.getMonth() + 1); date.setDate(1); return date; } }
      ]
    }
  },
  computed: {
    filteredDoctors() {
      let filtered = [...this.doctors];

      // 根据号源类型过滤医生列表
      if (this.selectedType === 'general') {
        filtered = filtered.filter(doctor => doctor.type === 'general');
      } else if (this.selectedType === 'expert') {
        filtered = filtered.filter(doctor => doctor.type === 'expert');
      }

      // 根据搜索关键词过滤
      if (this.searchQuery) {
        filtered = filtered.filter(doctor =>
          doctor.name.includes(this.searchQuery)
        );
      }

      // 🎯 实时更新余号数量：统计该医生当前筛选条件下剩余可预约（未预约 + 未过期）号源数量
      const availableCountMap = {};
      this.filteredAndSortedTickets.forEach(ticket => {
        const doctorId = String(ticket.doctorId || ticket.doctor_id);
        if (!availableCountMap[doctorId]) {
          availableCountMap[doctorId] = 0;
        }
        // 只有未预约的号源才算作可预约余号
        if (ticket.status === '未预约') {
          availableCountMap[doctorId]++;
        }
      });

      // 更新每个医生的余号数量
      filtered = filtered.map(doctor => {
        const actualAvailable = availableCountMap[String(doctor.id)] || 0;
        return {
          ...doctor,
          available: actualAvailable
        };
      });

      return filtered;
    },
    // 过滤并排序后的完整号源列表
    filteredAndSortedTickets() {
      let filtered = [...this.tickets];

      // 🎯 精确过滤：过滤掉早于当前时间的号源
      // - 日期早于今天 → 过滤
      // - 日期是今天但号源时段已经开始（开始时间早于当前时间） → 过滤
      const now = new Date();

      filtered = filtered.filter(ticket => {
        // dateTime 格式示例："2024-01-01 08:00-09:00"
        const parts = (ticket.dateTime || '').split(' ');
        if (parts.length < 2) return true; // 如果格式不正确，保留显示

        const dateStr = parts[0];
        const timeRangeStr = parts[1];
        if (!dateStr || !timeRangeStr) return true;

        // 提取开始时间
        const startTimeStr = timeRangeStr.split('-')[0]; // "08:00"
        if (!startTimeStr) return true;

        // 构建号源开始时间的完整 Date 对象
        const ticketStartStr = `${dateStr} ${startTimeStr}`;
        const ticketStart = new Date(ticketStartStr);

        // 只显示开始时间晚于当前时间的号源
        return ticketStart > now;
      });

      // 🎯 按开始时间升序排序 → 较早的号源排在前面
      filtered.sort((a, b) => {
        const getStartTime = (ticket) => {
          const parts = (ticket.dateTime || '').split(' ');
          if (parts.length < 2) return new Date(0).getTime();
          const dateStr = parts[0];
          const timeRangeStr = parts[1];
          const startTimeStr = (timeRangeStr || '').split('-')[0];
          if (!startTimeStr) return new Date(0).getTime();
          const ticketStartStr = `${dateStr} ${startTimeStr}`;
          return new Date(ticketStartStr).getTime();
        };

        const timeA = getStartTime(a);
        const timeB = getStartTime(b);
        return timeA - timeB;
      });

      return filtered;
    },
    // 🎯 分页：按照用户选择的每页条数分页，返回当前页的数据
    filteredTickets() {
      const filtered = this.filteredAndSortedTickets;
      const startIndex = (this.currentPage - 1) * this.pageSize;
      const endIndex = startIndex + this.pageSize;
      return filtered.slice(startIndex, endIndex);
    },
    // 更新总条数为过滤后的实际条数，分页自动处理
    totalTickets() {
      return this.filteredAndSortedTickets.length;
    },
    hasSearchCriteria() {
      return !!this.patientKeyword?.trim();
    }
  },
  methods: {
    selectDoctor(doctorId) {
      this.selectedDoctorId = this.selectedDoctorId === doctorId ? null : doctorId;
      this.currentPage = 1;
      this.fetchTickets({ refreshDepartments: false, refreshDoctors: false }).catch(() => {});
    },
    onTypeChange() {
      this.onSearch();
    },
    onDepartmentChange() {
      this.onSearch();
    },
    onDoctorSearch() {
      // 使用计算属性实时过滤
    },
    onDateChange() {
      this.onSearch();
    },
    openPatientSelectModal(ticketId) {
      this.currentTicket = this.tickets.find(ticket => ticket.slot_id === ticketId);
      this.patientKeyword = '';
      this.patients = [];
      this.selectedPatientId = null;
      this.selectedPatient = null;
      this.showPatientModal = true;
      this.searchPatients();
    },
    getPatientUniqueId(patient, index = null) {
      return patient.id || patient.patientId || patient.identifierNo || patient.medicalCard || patient.idCard ||
        (index !== null ? `temp_${index}` : null);
    },
    matchPatientKeyword(patient, keyword) {
      const normalizedKeyword = String(keyword || '').trim().toLowerCase();
      if (!normalizedKeyword) {
        return true;
      }
      const fields = [
        patient.name,
        patient.id,
        patient.patientId,
        patient.identifierNo,
        patient.medicalCard,
        patient.idCard,
        patient.phone
      ];
      return fields.some(field => String(field || '').toLowerCase().includes(normalizedKeyword));
    },
    searchPatients() {
      const keyword = this.patientKeyword?.trim() || '';
      const requestParams = keyword ? { searchKey: keyword } : {};
      this.isLoading = true;
      getPatientList(requestParams).then(response => {
        let records = [];
        if (response.data && response.data.records) {
          records = response.data.records;
        } else if (response.data && Array.isArray(response.data)) {
          records = response.data;
        } else if (Array.isArray(response)) {
          records = response;
        }

        this.patients = records
          .filter(patient => this.matchPatientKeyword(patient, keyword))
          .map((patient, index) => {
            const rowKey = this.getPatientUniqueId(patient, index);
            return {
              ...patient,
              // 统一口径：预约场景的就诊卡号使用患者标识表中的 identifierNo
              medicalCard: patient.identifierNo || patient.medicalCard || '',
              _rowKey: rowKey
            };
          });

        this.patients.forEach((patient, index) => {
          if (!patient.idCard) {
            patient.idCard = patient._rowKey || `temp_${index}`;
          }
        });

        if (keyword && this.patients.length === 0) {
          ElMessage.warning('未找到符合条件的患者');
        }
      }).catch(error => {
        this.patients = [];
        ElMessage.error('获取患者列表失败：' + (error.message || '未知错误'));
      }).finally(() => {
        this.isLoading = false;
      });
    },
    resetPatientSearch() {
      this.patientKeyword = '';
      this.selectedPatientId = null;
      this.selectedPatient = null;
      this.searchPatients();
    },
    
    // 双击未预约卡片触发患者选择流程
    handleDoubleClick(ticket) {
      if (ticket.status === '未预约') {
        this.currentTicket = ticket;
        this.patientKeyword = '';
        this.selectedPatientId = null;
        this.selectedPatient = null;  
        // 先打开弹窗，再加载患者数据，避免等待
        this.showPatientModal = true;
        // 调用患者搜索接口，加载患者列表
        this.searchPatients();
      }
    },
    
    // 右键已预约卡片显示取消预约菜单
    handleRightClick(event, ticket) {
      if (ticket.status === '已预约') {
        this.selectedTicketForCancel = ticket;
        this.contextMenuPosition = { x: event.clientX, y: event.clientY };
        this.contextMenuVisible = true;
      }
    },
    
    // 关闭右键菜单
    closeContextMenu() {
      this.contextMenuVisible = false;
      this.selectedTicketForCancel = null;
    },
    
    // 确认取消预约
    confirmCancelAppointment() {
      if (this.selectedTicketForCancel) {
        // 使用 ElMessageBox.confirm 进行二次确认，显示患者姓名
        ElMessageBox.confirm(
          `确认取消患者${this.selectedTicketForCancel.patientName || ''}的预约？`,
          '系统提示',
          {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }
        ).then(() => {
          // 用户点击确定，调用API取消预约
          this.cancelAppointment(this.selectedTicketForCancel);
        }).catch(() => {
          // 用户取消操作
          this.closeContextMenu();
        });
      }
    },
    
    // 取消预约API调用
    cancelAppointment(ticket) {
      if (!ticket || !ticket.slot_id) {
        ElMessage.error('取消预约失败：缺少号源信息');
        this.closeContextMenu();
        return;
      }
      
      // 使用真实API调用取消预约，传递slot_id
      cancelTicket(ticket.slot_id).then(response => {        
        // 根据后端返回判断是否成功
        if (response.code === 200 || response.msg === '取消成功' || response.message === '取消成功') {
          console.log('取消预约成功，更新前端状态');
          
          // API调用成功后，更新当前卡片状态
          const ticketIndex = this.tickets.findIndex(t => t.slot_id === ticket.slot_id);
          if (ticketIndex !== -1) {
            // 清除该号源关联的所有患者信息
            this.tickets[ticketIndex].status = '未预约';
            this.tickets[ticketIndex].patientName = null;
            this.tickets[ticketIndex].patientId = null;
            this.tickets[ticketIndex].patientGender = null;
            this.tickets[ticketIndex].gender = null;
            this.tickets[ticketIndex].medicalCard = null;
            this.tickets[ticketIndex].phone = null;
          }

          this.fetchTickets({ refreshDepartments: false, refreshDoctors: true }).catch(() => {});
          
          // 关闭上下文菜单
          this.closeContextMenu();
          ElMessage.success('预约已取消，号源已释放');
        } else {
          // 取消失败
          const errorMsg = response.msg || response.message || '取消预约失败';
          ElMessage.error(`取消预约失败：${errorMsg}`);
          this.closeContextMenu();
        }
      }).catch(error => {
        console.error('取消预约失败:', error);
        this.closeContextMenu();
      });
    },
    closePatientSelectModal() {
      this.showPatientModal = false;
      this.selectedPatientId = null;
      this.selectedPatient = null;
    },
    selectPatient(patientId) {
      if (this.patients.length === 0) {
        ElMessage.error('患者数据未加载，请先搜索患者');
        return;
      }
      this.selectedPatientId = patientId;
      this.selectedPatient = this.patients.find(patient => patient._rowKey === patientId);
      if (this.selectedPatient) {
        ElMessage.success('已选中患者: ' + this.selectedPatient.name);
      } else {
        ElMessage.error('未找到该患者，请重新选择');
        this.selectedPatientId = null;
      }
    },
    confirmPatientSelection() {
      if (!this.selectedPatientId || !this.selectedPatient) {
        ElMessage.error('请选择患者');
        return;
      }

      if (!this.currentTicket) {
        ElMessage.error('预约信息错误，请重新选择号源');
        this.closePatientSelectModal();
        return;
      }

      // 再次验证号源是否仍处于可预约状态
      if (this.currentTicket.status !== '未预约') {
        ElMessage.error('该号源已被预约，请选择其他号源');
        this.closePatientSelectModal();
        return;
      }

      try {
        const userStore = useUserStore();
        const patientPrimaryId = this.selectedPatient.id || this.selectedPatient.patientId;
        const medicalCard = this.selectedPatient.identifierNo || this.selectedPatient.medicalCard;
        if (!patientPrimaryId) {
          ElMessage.error('患者ID缺失，无法预约，请重新选择患者');
          return;
        }
        if (!medicalCard) {
          ElMessage.error('就诊卡号缺失，无法预约，请先维护患者就诊卡号');
          return;
        }
        const appointmentData = {
          ticketId: this.currentTicket.slot_id,
          slotId: this.currentTicket.slot_id,
          patientId: patientPrimaryId,
          patientName: this.selectedPatient.name,
          medicalCard,
          phone: this.selectedPatient.phone,
          gender: this.getGenderValueForBackend(this.selectedPatient),
          fee: Number(this.currentTicket.fee) || 0,
          regType: this.currentTicket.ticketType === 'general' ? '普通' : '专家',
          tenant_id: userStore.tenantId || '1'
        };

        // 验证必填字段
        if (!appointmentData.ticketId) {
          ElMessage.error('号源ID无效');
          return;
        }

        bookTicket(appointmentData).then(() => {
          const ticketIndex = this.tickets.findIndex(t => t.slot_id === this.currentTicket.slot_id);
          if (ticketIndex !== -1) {
            this.tickets[ticketIndex].status = '已预约';
            this.tickets[ticketIndex].patientName = this.selectedPatient.name;
            this.tickets[ticketIndex].patientId = medicalCard;
            this.tickets[ticketIndex].patientGender = this.selectedPatient.genderEnum_enumText || this.selectedPatient.genderEnum || this.selectedPatient.gender || this.selectedPatient.sex;
            this.tickets[ticketIndex].gender = this.getGenderText(this.tickets[ticketIndex].patientGender);
          }

          this.closePatientSelectModal();

          // 重新加载号源数据，确保显示最新状态
          this.onSearch();

          ElMessage.success('预约成功，号源已锁定。患者到院签到时需缴费取号。');
        }).catch(error => {
          console.error('预约失败:', error);
        });
      } catch (error) {
        console.error('操作异常:', error);
      }
    },
    // 切换侧边栏显示/隐藏
    toggleSidebar() {
      this.showSidebar = !this.showSidebar;
    },
    // 获取性别文本
    getGenderText(genderValue) {
      // 如果值为null或undefined，返回"未知"
      if (genderValue === null || genderValue === undefined) {
        return '未知';
      }
      
      // 将值转换为字符串进行比较
      const strValue = String(genderValue).toLowerCase();
      
      // 处理男性值
      if (strValue === '0' || strValue === '男' || strValue === 'male' || strValue === 'm' || 
          strValue === 'malegender' || strValue === 'man' || strValue === 'boy' || 
          strValue === '男性' || strValue === '男士') {
        return '男';
      }
      
      // 处理女性值
      if (strValue === '1' || strValue === '女' || strValue === 'female' || strValue === 'f' || 
          strValue === 'femalegender' || strValue === 'woman' || strValue === 'girl' || 
          strValue === '女性' || strValue === '女士') {
        return '女';
      }
      
      // 如果都不是，返回"未知"
      return '未知';
    },
    // 获取用于后端的性别值
    getGenderValueForBackend(patient) {
      // 优先使用数字类型的genderEnum或gender字段
      if (patient.genderEnum !== undefined && patient.genderEnum !== null) {
        return patient.genderEnum;
      }
      if (patient.gender !== undefined && patient.gender !== null) {
        return patient.gender;
      }
      
      // 如果genderEnum_enumText是"男性"或"女性"，转换为对应的数字
      if (patient.genderEnum_enumText) {
        const text = patient.genderEnum_enumText.toLowerCase();
        if (text === '男性' || text === '男') {
          return 0;
        } else if (text === '女性' || text === '女') {
          return 1;
        }
      }
      // 默认返回0（男性）
      return 0;
    },
    
    // 检测是否为移动设备
    checkMobileDevice() {
      this.isMobile = window.innerWidth <= 768;
    },
    getStatusClass(status) {
      return STATUS_CLASS_MAP[status] || 'status-unbooked';
    },
    buildQueryParams(page = this.currentPage) {
      const doctorId =
        this.selectedDoctorId === null || this.selectedDoctorId === undefined || this.selectedDoctorId === ''
          ? null
          : String(this.selectedDoctorId);
      return {
        date: this.selectedDate,
        status: this.selectedStatus === 'all' ? null : this.selectedStatus,
        type: this.selectedType === 'all' ? null : this.selectedType,
        department: this.selectedDepartment === 'all' ? null : this.selectedDepartment,
        doctorId,
        name: this.patientName?.trim() || null,
        card: this.patientCard?.trim() || null,
        phone: this.patientPhone?.trim() || null,
        page,
        limit: this.pageSize
      };
    },
    buildDoctorQueryParams() {
      return {
        date: this.selectedDate,
        type: this.selectedType === 'all' ? null : this.selectedType,
        department: this.selectedDepartment === 'all' ? null : this.selectedDepartment
      };
    },
    handleTicketResponse(ticketResponse) {
      const payload = (() => {
        if (!ticketResponse) return null;
        if (ticketResponse.list || ticketResponse.records || ticketResponse.total !== undefined) {
          return ticketResponse;
        }
        if (ticketResponse.data?.list || ticketResponse.data?.records || ticketResponse.data?.total !== undefined) {
          return ticketResponse.data;
        }
        if (ticketResponse.data?.data) {
          return ticketResponse.data.data;
        }
        return ticketResponse.data || ticketResponse;
      })();

      if (!payload) {
        this.tickets = [];
        this.allTickets = [];
        this.totalTickets = 0;
        return;
      }
      const records = payload.list || payload.records || [];
      const filteredRecords = this.applyStatusFilter(records);
      const total = Number(payload.total);
      this.tickets = [...filteredRecords];
      this.allTickets = [...filteredRecords];
      // 后端已经分页，总条数由后端返回，始终使用后端返回的total
      this.totalTickets = Number.isFinite(total) ? total : this.tickets.length;
    },
    applyStatusFilter(records = []) {
      if (!Array.isArray(records) || records.length === 0) {
        return [];
      }
      if (!this.selectedStatus || this.selectedStatus === 'all') {
        return records;
      }
      const statusMap = {
        unbooked: ['未预约'],
        booked: ['已预约'],
        checked: ['已取号'],
        cancelled: ['已停诊', '已取消'],
        returned: ['已退号']
      };
      const matchedStatusList = statusMap[this.selectedStatus] || [];
      if (matchedStatusList.length === 0) {
        return records;
      }
      return records.filter(item => matchedStatusList.includes(item?.status));
    },
    updateDoctorsListFromApi(doctorResponse) {
      let doctorList = [];
      const data = doctorResponse?.data;
      if (Array.isArray(doctorResponse)) {
        doctorList = doctorResponse;
      } else if (Array.isArray(data)) {
        doctorList = data;
      } else if (Array.isArray(data?.list)) {
        doctorList = data.list;
      } else if (Array.isArray(data?.records)) {
        doctorList = data.records;
      } else if (Array.isArray(data?.data)) {
        doctorList = data.data;
      }

      this.doctors = doctorList
        .map((doctor, index) => {
          const id = doctor?.id ?? doctor?.doctorId ?? index;
          const available = Number(doctor?.available ?? doctor?.availableNum ?? doctor?.available_num ?? 0);
          return {
            id: String(id),
            name: doctor?.name || doctor?.doctorName || '',
            available: Number.isFinite(available) ? available : 0,
            type: doctor?.type || doctor?.ticketType || 'general'
          };
        })
        .filter(doctor => !!doctor.name);

      if (this.selectedDoctorId && !this.doctors.some(d => d.id === this.selectedDoctorId)) {
        this.selectedDoctorId = null;
      }
    },
    fetchTickets({ refreshDepartments = false, refreshDoctors = false } = {}) {
      this.isLoading = true;
      const ticketPromise = listTicket(this.buildQueryParams(this.currentPage));
      const deptPromise = refreshDepartments
        ? listRegisterOrganizations({
            pageNum: 1,
            pageSize: 200
          })
        : Promise.resolve(null);
      const doctorPromise = refreshDoctors
        ? listDoctorSummary(this.buildDoctorQueryParams())
        : Promise.resolve(null);

      return Promise.all([ticketPromise, deptPromise, doctorPromise]).then(([ticketResponse, deptResponse, doctorResponse]) => {
        this.handleTicketResponse(ticketResponse);
        if (refreshDepartments) {
          this.updateDepartmentsListFromApi(deptResponse);
        }
        if (refreshDoctors) {
          this.updateDoctorsListFromApi(doctorResponse);
        }
      }).catch(error => {
        console.error('获取数据失败:', error);
        this.tickets = [];
        this.allTickets = [];
        this.totalTickets = 0;
        throw error;
      }).finally(() => {
        this.isLoading = false;
      });
    },
    onSearch() {
      if (this.isLoading) {
        return;
      }
      this.currentPage = 1;
      this.fetchTickets({ refreshDepartments: true, refreshDoctors: true }).catch(() => {});
    },
    handlePageChange(page) {
      if (this.isLoading || page === this.currentPage) {
        return;
      }
      this.currentPage = page;
      this.fetchTickets({ refreshDepartments: false, refreshDoctors: false }).catch(() => {});
    },
    handlePageSizeChange(size) {
      if (this.isLoading || size === this.pageSize) {
        return;
      }
      this.pageSize = size;
      this.currentPage = 1;
      this.fetchTickets({ refreshDepartments: false, refreshDoctors: false }).catch(() => {});
    },
    updateDepartmentsListFromApi(deptResponse) {
      let deptList = [];
      const data = deptResponse?.data;
      if (Array.isArray(data)) {
        deptList = data;
      } else if (Array.isArray(data?.records)) {
        deptList = data.records;
      } else if (Array.isArray(data?.list)) {
        deptList = data.list;
      } else if (Array.isArray(data?.content)) {
        deptList = data.content;
      } else if (Array.isArray(data?.data)) {
        deptList = data.data;
      }
      if (deptList.length > 0) {
        const departmentArray = deptList
          .map(item => {
            const deptName = item?.deptName || item?.name;
            return deptName ? { value: deptName, label: deptName } : null;
          })
          .filter(Boolean)
          .filter((dept, index, self) => index === self.findIndex(d => d.value === dept.value));
        this.departments = [{ value: 'all', label: '全部科室' }, ...departmentArray];
      } else {
        this.departments = [{ value: 'all', label: '全部科室' }];
      }
    }
  },
  mounted() {
    document.addEventListener('click', this.closeContextMenu);
    // 初始化数据
    this.selectedDate = new Date().toISOString().split('T')[0];
    // 调用onSearch获取初始数据
    this.onSearch();
    // 检测是否为移动设备
    this.checkMobileDevice();
    // 监听窗口大小变化
    window.addEventListener('resize', this.checkMobileDevice);
  },
  beforeUnmount() {
    document.removeEventListener('click', this.closeContextMenu);
    // 移除窗口大小变化监听
    window.removeEventListener('resize', this.checkMobileDevice);
  }
}
</script>

<style scoped>
/* 颜色变量定义 */
:root {
  --primary-color: #1890FF;
  --secondary-color: #FF6B35;
  --status-unbooked: #5A8DEE;
  --status-booked: #FAAD14;
  --status-checked: #52C41A;
  --status-cancelled: #F5222D;
  --border-color: #d9d9d9;
  --text-primary: #333;
  --text-secondary: #666;
  --text-tertiary: #999;
  --bg-light: #f8f9fa;
  --bg-white: #fff;
  --shadow: 0 2px 8px rgba(90, 141, 238, 0.08);
}

/* 基础样式 */
.ticket-management-container {
  padding: 20px;
  background-color: var(--bg-light);
  min-height: 100vh;
}

/* 顶部搜索区域 */
.top-search-area {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 20px;
  padding: 12px 16px;
  background-color: #FFFFFF;
  border-radius: 4px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  border: 1px solid #E8E8E8;
}

/* 搜索标签行 */
.search-labels {
  display: flex;
  gap: 12px;
  align-items: center;
}

/* 搜索标签样式 */
.search-label {
  font-size: 14px;
  color: #333333;
  font-weight: 500;
  text-align: left;
  flex-grow: 1;
  min-width: 80px;
}

/* 搜索输入行 */
.search-inputs {
  display: flex;
  gap: 12px;
  align-items: center;
}

/* 为输入行的每个容器设置flex-grow，使其均匀分布 */
.search-inputs > div {
  flex-grow: 1;
  min-width: 100px;
}

.hamburger-menu {
  display: none;
  cursor: pointer;
  font-size: 20px;
  color: var(--primary-color);
}

.date-picker {
  width: 100%;
}

/* 搜索控件样式 */
.search-input {
  padding: 6px 12px;
  border: 1px solid #E8E8E8;
  border-radius: 4px;
  font-size: 14px;
  background-color: #FFFFFF;
  width: 100%;
  height: 32px;
  box-sizing: border-box;
}

.search-input:focus {
  border-color: #1890FF;
  outline: none;
  box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}

.search-select {
  padding: 6px 12px;
  border: 1px solid #E8E8E8;
  border-radius: 4px;
  font-size: 14px;
  background-color: #FFFFFF;
  cursor: pointer;
  width: 100%;
  height: 32px;
  box-sizing: border-box;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23999' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 12px;
}

.search-select:focus {
  border-color: #1890FF;
  outline: none;
  box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}

.search-btn {
  padding: 0 16px;
  background-color: #1890FF;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  height: 32px;
  box-sizing: border-box;
  transition: background-color 0.3s;
}

.search-btn:hover {
  background-color: #40a9ff;
}

.search-btn:active {
  background-color: #096dd9;
}

.search-btn:disabled {
  background-color: #e6f7ff;
  color: #91d5ff;
  cursor: not-allowed;
}

/* 日期选择器样式 */
.date-picker {
  width: 160px;
  z-index: 1;
}

/* 状态筛选器样式 */
.status-filter {
  z-index: 2;
}

.el-date-editor {
  width: 100% !important;
}

.el-date-editor .el-input__inner {
  height: 32px !important;
  border-radius: 4px;
  border: 1px solid #E8E8E8;
  font-size: 14px;
  padding: 0 36px 0 12px !important;
}

.el-date-editor .el-input__inner:focus {
  border-color: #1890FF;
  outline: none;
  box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}

.el-date-editor .el-input__suffix {
  right: 8px !important;
  top: 50%;
  transform: translateY(-50%);
}

.el-date-editor .el-input__suffix-inner {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 主要内容区域 */
.main-content {
  display: flex;
  gap: 20px;
  height: calc(100vh - 104px); /* 减去顶部搜索区域高度和内边距 */
  overflow: hidden;
}

.left-sidebar {
  width: 220px;
  height: 100%;
  background-color: white;
  border-radius: 8px;
  padding: 20px;
  box-shadow: var(--shadow);
  flex-shrink: 0;
  transition: all 0.3s ease;
  overflow-y: auto; /* 当内容超出高度时显示滚动条 */
}

/* 移动端侧边栏样式 */
.sidebar-mobile {
  position: fixed;
  left: 0;
  top: 0;
  height: 100vh;
  z-index: 1000;
}

/* 侧边栏隐藏样式 */
.sidebar-hidden {
  transform: translateX(-100%);
}

.right-content {
  flex: 1;
  background-color: white;
  border-radius: 8px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  transition: all 0.3s ease;
}

/* 移动端右侧内容区占满屏幕 */
.right-content-full {
  width: 100%;
}

  /* 响应式设计 */
  @media (max-width: 768px) {
    /* 顶部搜索区域改为纵向排列 */
    .top-search-area {
      flex-direction: column;
      height: auto;
      padding: 16px;
      gap: 16px;
    }

    /* 汉堡菜单显示 */
    .hamburger-menu {
      display: block;
      align-self: flex-start;
    }

    /* 搜索区域元素宽度100% */
    .date-picker,
    .status-filter,
    .patient-search,
    .card-search,
    .phone-search,
    .search-button,
    .add-patient {
      width: 100%;
    }

    /* 右侧内容区卡片布局调整 */
    .virtual-list {
      grid-template-columns: 1fr;
      gap: 12px;
      padding: 12px;
    }

    /* 左侧边栏默认隐藏 */
    .left-sidebar {
      transform: translateX(-100%);
    }

    /* 右侧内容区占满屏幕 */
     .right-content {
       width: 100%;
     }
   }
   
   /* 确保卡片样式正确应用 */
   .ticket-card {
     box-shadow: var(--shadow);
     overflow: visible;
     transition: all 0.3s ease;
   }
   
   /* 卡片悬停效果 */
   .ticket-card:hover {
     transform: translateY(-2px);
     box-shadow: 0 4px 16px rgba(90, 141, 238, 0.12);
   }
   
   /* 按钮悬停效果 */
   .search-btn,
   .add-patient-btn {
     transition: all 0.3s ease;
   }
   
   .search-btn:hover,
   .add-patient-btn:hover {
     transform: translateY(-1px);
     box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
   }
   
   /* 输入框焦点效果 */
   .search-input {
     transition: all 0.3s ease;
   }
   
   .search-input:focus {
     border-color: var(--primary-color);
     box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
   }
   
   /* 医生列表项悬停效果 */
   .doctor-item {
     transition: all 0.3s ease;
   }
   
   .doctor-item:hover {
     background-color: rgba(24, 144, 255, 0.05);
     cursor: pointer;
   }
   
   /* 医生列表项选中效果 */
.doctor-item.selected {
  background-color: rgba(24, 144, 255, 0.2);
  border-left: 4px solid var(--primary-color);
  font-weight: 600;
}
   
   /* 加载动画 */
   .loading-container {
     display: flex;
     justify-content: center;
     align-items: center;
     padding: 20px;
     gap: 8px;
     color: var(--primary-color);
   }
   
   .loading-spinner {
     width: 16px;
     height: 16px;
     border: 2px solid rgba(24, 144, 255, 0.2);
     border-top-color: var(--primary-color);
     border-radius: 50%;
     animation: spin 0.8s linear infinite;
   }
   
   @keyframes spin {
     to { transform: rotate(360deg); }
   }

/* 左侧筛选区域 */
.section {
  margin-bottom: 24px;
}

.section-title {
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 12px;
  color: #333;
}

.radio-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.radio-group label {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}

.doctor-list {
  margin-top: 12px;
  max-height: calc(100vh - 300px); /* 限制医生列表高度 */
  overflow-y: auto; /* 当内容超出高度时显示滚动条 */
}

.doctor-item {
  padding: 12px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s ease;
  margin-bottom: 8px;
}

.doctor-item:hover {
  background-color: #f0f7ff;
}

.doctor-item.selected {
  background-color: #e6f2ff;
  border-left: 4px solid var(--primary-color);
}

.doctor-name {
  font-weight: 500;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.doctor-available {
  font-size: 12px;
  color: var(--status-unbooked);
  font-weight: normal;
}

/* 右侧号源卡片网格布局 */
.ticket-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
  padding: 8px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  align-content: start;
}

  /* 加载更多样式 */
  .loading-more,
  .no-more {
    grid-column: 1 / -1;
    text-align: center;
    padding: 20px;
    color: #999;
    font-size: 14px;
  }

.empty-state {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 600px;
  color: var(--text-tertiary);
}

.empty-text {
  font-size: 16px;
}

.ticket-card {
  background: white;
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 2px 8px rgba(90, 141, 238, 0.08);
  border: 1px solid #e8e8e8;
  transition: all 0.3s ease;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  position: relative;
  min-height: 210px;
  height: auto;
}

.ticket-card:hover {
  box-shadow: 0 4px 12px rgba(90, 141, 238, 0.12);
  transform: translateY(-2px);
  border-color: #1890ff;
}

.ticket-number {
  position: absolute;
  top: 12px;
  left: 12px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background-color: #e6f7ff;
  color: #1890ff;
  font-size: 12px;
  font-weight: 500;
  display: flex;
  justify-content: center;
  align-items: center;
}

.ticket-index {
  position: absolute;
  top: 12px;
  left: 12px;
  color: #1890ff;
  font-size: 14px;
  font-weight: bold;
}

.ticket-time {
  font-size: 14px;
  color: #333;
  font-weight: 500;
  margin: 8px 0;
}

.ticket-status {
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 500;
  text-align: center;
  min-width: 60px;
  margin-bottom: 8px;
}

.status-unbooked {
  background-color: #e6f3ff;
  color: #1890ff;
}

.status-locked {
  background-color: #fff1f0;
  color: #f5222d;
}

.status-booked {
  background-color: #fff8e6;
  color: #fa8c16;
}

.status-checked {
  background-color: #f6ffed;
  color: #52c41a;
}

.status-returned {
  background-color: #fff7e6;
  color: #d46b08;
}

.status-cancelled {
  background-color: #fff1f0;
  color: #ff4d4f;
}

.ticket-doctor {
  font-size: 14px;
  color: #333;
  margin-bottom: 8px;
  text-align: center;
  width: 100%;
  line-height: 1.35;
  white-space: normal;
  word-break: break-word;
}

.ticket-department {
  font-size: 12px;
  color: #666;
  margin-bottom: 8px;
  text-align: center;
  width: 100%;
  line-height: 1.35;
  white-space: normal;
  word-break: break-word;
}

.ticket-id-time {
  font-size: 14px;
  color: #333;
  margin-bottom: 8px;
  text-align: center;
}

.ticket-fee {
  font-size: 14px;
  color: #333;
  margin-bottom: 8px;
  width: 100%;
  text-align: center;
  line-height: 1.35;
  white-space: normal;
  word-break: break-word;
}

.ticket-type {
  font-size: 12px;
  color: #999;
  margin-bottom: 12px;
  width: 100%;
  text-align: center;
}

.ticket-actions {
  margin-top: auto;
  padding-top: 8px;
  width: 100%;
  display: flex;
  justify-content: center;
}

.book-button {
      padding: 4px 16px;
      background-color: #1890ff;
      color: white;
      border: none;
      border-radius: 4px;
      font-size: 12px;
      cursor: pointer;
      transition: all 0.3s ease;
      align-self: center;
    }

    .book-button:hover:not(:disabled) {
      background-color: #40a9ff;
    }

    .book-button:disabled {
      background-color: #e6f7ff;
      color: #91d5ff;
      cursor: not-allowed;
    }

/* 患者信息样式 */
.ticket-patient {
  margin-top: 8px;
  padding: 4px;
  background-color: rgba(24, 144, 255, 0.05);
  border-radius: 4px;
  font-size: 12px;
  text-align: center;
  color: #333;
  width: 100%;
  line-height: 1.35;
  white-space: normal;
  word-break: break-word;
}

/* 患者电话号码样式 */
.ticket-phone {
  margin-top: 4px;
  padding: 4px;
  background-color: rgba(34, 177, 76, 0.05);
  border-radius: 4px;
  font-size: 12px;
  text-align: center;
  color: #22b14c;
  font-weight: 500;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .ticket-grid {
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 12px;
  }
  
  .ticket-card {
    padding: 12px;
    min-height: 190px;
  }
  
  .ticket-doctor {
    font-size: 13px;
  }
  
  .ticket-id-time {
    font-size: 13px;
  }
  
  .ticket-index {
    font-size: 13px;
  }
}

/* 弹窗样式 */
.modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal-content {
  background-color: white;
  border-radius: 8px;
  width: 80%;
  max-width: 800px;
  /* 使用固定高度计算，确保footer始终可见 */
  height: 80vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* 确保弹窗在视口中居中且不被遮挡 */
  margin: 20px;
  /* 相对定位，为绝对定位的footer提供参考 */
  position: relative;
}

.modal-header {
  flex-shrink: 0;
}

.modal-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
  /* 给body添加底部内边距，确保内容不被footer遮挡 */
  padding-bottom: 100px;
}

.modal-footer {
  flex-shrink: 0;
  /* 确保footer始终在底部可见，不受其他元素影响 */
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 10;
  padding: 16px 20px;
  border-top: 1px solid var(--border-color);
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  background-color: white;
  /* 添加阴影，增强视觉层次感 */
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
  /* 确保footer不被body内容遮挡 */
}

.confirm-btn {
  padding: 8px 24px;
  background-color: #1890ff;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  transition: background-color 0.3s;
  font-weight: 500;
  box-shadow: 0 2px 4px rgba(24, 144, 255, 0.2);
}

.confirm-btn:hover {
  background-color: #40a9ff;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3);
}

.confirm-btn:active {
  background-color: #096dd9;
  transform: translateY(0);
}

.cancel-btn {
  padding: 8px 24px;
  background-color: white;
  color: var(--text-secondary);
  border: 1px solid var(--border-color);
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.3s;
}

.cancel-btn:hover {
  color: var(--primary-color);
  border-color: var(--primary-color);
}

.modal-header {
  padding: 16px 20px;
  border-bottom: 1px solid #e0e0e0;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.modal-header h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
}

.close-btn {
  background: none;
  border: none;
  font-size: 24px;
  cursor: pointer;
  color: #999;
}

.modal-body {
  padding: 20px;
}

.patient-search-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
}

.patient-keyword-input {
  flex: 1;
}

.reset-btn {
  padding: 0 16px;
  background-color: #f5f5f5;
  color: #333;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  height: 32px;
  box-sizing: border-box;
  transition: all 0.3s;
}

.reset-btn:hover {
  border-color: #40a9ff;
  color: #1890ff;
  background-color: #f0f7ff;
}

.patient-table-container {
  margin-top: 20px;
  overflow-x: auto;
}

.patient-table {
  width: 100%;
  border-collapse: collapse;
}

.patient-table th,
.patient-table td {
  padding: 12px;
  text-align: left;
  border-bottom: 1px solid #e0e0e0;
}

.patient-table th {
  background-color: #f5f5f5;
  font-weight: 600;
}

.patient-table tr:hover {
  background-color: #fafafa;
}

.patient-table tr.selected {
  background-color: #d6e8ff;
}

.patient-table tr.selected td {
  background-color: #d6e8ff;
  color: #0f3f8f;
  font-weight: 600;
}

.patient-table tr.selected td:first-child {
  box-shadow: inset 4px 0 0 #1677ff;
}

.patient-table tr.selected:hover td {
  background-color: #c9e1ff;
}

.select-btn {
  padding: 6px 12px;
  background-color: #1890ff;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 500;
  box-shadow: 0 2px 4px rgba(24, 144, 255, 0.2);
}

.select-btn:hover:not(:disabled) {
  background-color: #40a9ff;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3);
}

.select-btn:disabled {
  background-color: #d9d9d9;
  color: #fff;
  cursor: not-allowed;
  box-shadow: none;
}

/* 搜索提示样式 */
.search-hint {
  text-align: center;
  color: #999;
  font-size: 14px;
  padding: 20px;
  background-color: #fafafa;
  border-radius: 4px;
  margin: 10px 0;
}

/* 加载指示器样式 */
.loading-indicator {
  text-align: center;
  color: #666;
  font-size: 14px;
  padding: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.loading-spinner {
  width: 16px;
  height: 16px;
  border: 2px solid #f3f3f3;
  border-top: 2px solid #1890ff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.no-results {
  text-align: center;
  color: #666;
  font-size: 14px;
  padding: 20px;
  background-color: #fff2f0;
  border: 1px solid #ffccc7;
  border-radius: 4px;
  margin: 10px 0;
}

/* 右键菜单样式 */
.context-menu {
  position: fixed;
  background-color: white;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  z-index: 1001;
}

.menu-item {
  padding: 8px 16px;
  cursor: pointer;
  font-size: 14px;
  transition: background-color 0.2s;
}

.menu-item:hover {
  background-color: #f5f5f5;
}

.context-menu-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1000;
}

.loading-text {
  display: flex;
  align-items: center;
}

.search-btn:disabled {
  opacity: 0.7;
  cursor: not-allowed;
}

/* 分页组件样式 */
.pagination-container {
  display: flex;
  justify-content: center;
  margin-top: 12px;
  padding: 20px 0;
  background-color: #fafafa;
  border-radius: 4px;
  flex-shrink: 0;
}

.pagination-container .el-pagination {
  font-size: 14px;
}

.pagination-container .el-pagination .el-pager li {
  min-width: 36px;
  height: 36px;
  line-height: 36px;
  border-radius: 4px;
  margin: 0 2px;
}

.pagination-container .el-pagination .el-pager li:hover {
  background-color: #e6f7ff;
  color: #1890ff;
}

.pagination-container .el-pagination .el-pager li.active {
  background-color: #1890ff;
  color: white;
}

.pagination-container .el-pagination .btn-prev,
.pagination-container .el-pagination .btn-next {
  width: 36px;
  height: 36px;
  border-radius: 4px;
  margin: 0 2px;
}

.pagination-container .el-pagination .el-pagination__sizes {
  margin-right: 10px;
}

.pagination-container .el-pagination .el-pagination__sizes .el-input {
  width: 100px;
}

.pagination-container .el-pagination .el-pagination__jump {
  margin-left: 10px;
}

.pagination-container .el-pagination .el-pagination__jump .el-input {
  width: 60px;
}
</style>
