<script lang="ts" setup>
import type { Dayjs } from 'dayjs';

import { computed, ref, watch } from 'vue';

import { useVbenModal } from '@vben/common-ui';

import dayjs from 'dayjs';

import {
  Button,
  Checkbox,
  DatePicker,
  Input,
  Modal as AntModal,
  message,
  Radio,
  Select,
  Space,
  Tag,
} from 'ant-design-vue';

import { downloadByData } from '#/util/tool';

import {
  createOrderExportScheme,
  deleteOrderExportScheme,
  getOrderExportDataApi,
  getOrderExportSchemeList,
  getOrderPrescriptionTypeOption,
  getOrderStatusOption,
  type OrderExportDataParams,
  type OrderExportSchemeItem,
  updateOrderExportScheme,
} from '#/views/business/order/product-order/api';
import ProductOrderExportFieldSortModal from '#/views/business/order/product-order/components/ProductOrderExportFieldSortModal.vue';
import type { ExportGranularity } from '#/views/business/order/product-order/config/exportFields';
import {
  getDefaultSelectedKeys,
  getExportFields,
  granularityLabel,
  groupExportFields,
} from '#/views/business/order/product-order/config/exportFields';
import {
  buildDefaultOrderedKeys,
  formatFieldOrderPreview,
  syncOrderedSelectedKeys,
} from '#/views/business/order/product-order/utils/exportFieldOrder';
import {
  exportFilename,
  exportProductOrderExcel,
} from '#/views/business/order/product-order/utils/exportProductOrderExcel';
import {
  applySchemeToForm,
  buildSchemeConfigFromForm,
  findDefaultScheme,
  type ExportFormState,
} from '#/views/business/order/product-order/utils/exportScheme';
import { getStoreOption } from '#/views/system/store/api';

defineOptions({
  name: 'ProductOrderExportModal',
});

const CUSTOM_SCHEME_VALUE = 0;

const DELIVERY_OPTIONS = [
  { label: '快递到家', value: 0 },
  { label: '诊所自提', value: 1 },
];

const searchTime = ref<[Dayjs, Dayjs]>([dayjs().startOf('month'), dayjs()]);
const orderNo = ref('');
const storeId = ref<number | undefined>(undefined);
const status = ref<number | undefined>(undefined);
const deliveryMethod = ref<number | undefined>(undefined);
const prescriptionType = ref<number | undefined>(undefined);
const drugKeyword = ref('');
/** 就诊人/医生关键字（姓名或手机号模糊，后端 whereHas 关联表筛选） */
const patientKeyword = ref('');
const doctorKeyword = ref('');
const granularity = ref<ExportGranularity>('order');
/** 订单维度导出时，是否附加「订单商品明细」工作簿（按订单分组的每单商品清单） */
const withDetailWorkbook = ref(false);
const selectedKeys = ref<string[]>(getDefaultSelectedKeys('order'));
const orderedSelectedKeys = ref<string[]>(
  buildDefaultOrderedKeys(getDefaultSelectedKeys('order'), 'order'),
);
const fieldOrderCustomized = ref(false);
const loading = ref(false);
const loadingStep = ref('');

const storeOptions = ref<{ label: string; value: number }[]>([]);
const statusOptions = ref<{ label: string; value: number }[]>([]);
/** 订单类型选项：打开弹窗时从后端 ProductTypeEnum 拉取 */
const prescriptionTypeOptions = ref<{ label: string; value: number }[]>([]);
const fetchingStores = ref(false);
const storeExportLocked = ref(false);
const lockedStoreName = ref('');

const schemes = ref<OrderExportSchemeItem[]>([]);
const activeSchemeId = ref<number>(CUSTOM_SCHEME_VALUE);
const applyingScheme = ref(false);
const schemesLoading = ref(false);

const saveModalOpen = ref(false);
const saveModalLoading = ref(false);
const saveSchemeName = ref('');
const saveSchemeDefault = ref(false);
const sortModalOpen = ref(false);
const updateSchemeLoading = ref(false);
const defaultTagLoading = ref(false);
const schemeModified = ref(false);

const fieldList = computed(() => getExportFields(granularity.value));
const groupedFields = computed(() => groupExportFields(fieldList.value));
const selectedCount = computed(() => selectedKeys.value.length);
const totalFieldCount = computed(() => fieldList.value.length);

const fieldOrderPreview = computed(() =>
  orderedSelectedKeys.value.length > 0
    ? formatFieldOrderPreview(orderedSelectedKeys.value, fieldList.value)
    : '',
);

const schemeSelectOptions = computed(() => [
  { label: '自定义', value: CUSTOM_SCHEME_VALUE },
  ...schemes.value.map((s) => {
    let label = s.name;
    if (schemeModified.value && s.id === activeSchemeId.value) {
      label += '（已修改）';
    }
    return { label, value: s.id };
  }),
]);

const activeSavedScheme = computed(() =>
  schemes.value.find((s) => s.id === activeSchemeId.value),
);

const formState = (): ExportFormState => ({
  orderNo: orderNo.value,
  storeId: storeId.value,
  status: status.value,
  deliveryMethod: deliveryMethod.value,
  prescriptionType: prescriptionType.value,
  granularity: granularity.value,
  selectedKeys: selectedKeys.value,
  orderedSelectedKeys: orderedSelectedKeys.value,
});

function markSchemeModified() {
  if (activeSchemeId.value > CUSTOM_SCHEME_VALUE) {
    schemeModified.value = true;
  }
}

function clearSchemeModified() {
  schemeModified.value = false;
}

function syncOrderFromSelection() {
  orderedSelectedKeys.value = syncOrderedSelectedKeys(
    selectedKeys.value,
    orderedSelectedKeys.value,
    granularity.value,
    fieldOrderCustomized.value,
  );
}

function searchTimeRange(): [string, string] {
  return [
    searchTime.value[0].format('YYYY-MM-DD'),
    searchTime.value[1].format('YYYY-MM-DD'),
  ];
}

function labelOf(
  options: { label: string; value: number }[],
  value: number | undefined,
): string {
  if (value === undefined || value === null) {
    return '全部';
  }
  return options.find((o) => o.value === value)?.label ?? String(value);
}

function storeNameOf(id: number | undefined): string {
  if (id == null) {
    return '全部';
  }
  if (storeExportLocked.value && lockedStoreName.value) {
    return lockedStoreName.value;
  }
  return storeOptions.value.find((o) => o.value === id)?.label ?? String(id);
}

function selectedFieldLabels(): string {
  const labelMap = new Map(fieldList.value.map((f) => [f.key, f.label]));
  return orderedSelectedKeys.value
    .map((k) => labelMap.get(k) ?? k)
    .join('、');
}

function resetFormDefaults() {
  orderNo.value = '';
  status.value = undefined;
  deliveryMethod.value = undefined;
  prescriptionType.value = undefined;
  drugKeyword.value = '';
  patientKeyword.value = '';
  doctorKeyword.value = '';
  granularity.value = 'order';
  withDetailWorkbook.value = false;
  selectedKeys.value = getDefaultSelectedKeys('order');
  orderedSelectedKeys.value = buildDefaultOrderedKeys(
    selectedKeys.value,
    'order',
  );
  fieldOrderCustomized.value = false;
  if (!storeExportLocked.value) {
    storeId.value = undefined;
  }
}

function applyScheme(scheme: OrderExportSchemeItem) {
  applyingScheme.value = true;
  try {
    const state = formState();
    applySchemeToForm(scheme, state);
    granularity.value = state.granularity;
    orderNo.value = state.orderNo;
    if (!storeExportLocked.value) {
      storeId.value = state.storeId;
    }
    status.value = state.status;
    deliveryMethod.value = state.deliveryMethod;
    prescriptionType.value = state.prescriptionType;
    selectedKeys.value = state.selectedKeys;
    orderedSelectedKeys.value = state.orderedSelectedKeys;
    fieldOrderCustomized.value = true;
    clearSchemeModified();
  } finally {
    applyingScheme.value = false;
  }
}

async function loadSchemes(applyDefault = false) {
  schemesLoading.value = true;
  try {
    const list = await getOrderExportSchemeList();
    schemes.value = list ?? [];
    if (applyDefault) {
      const def = findDefaultScheme(schemes.value);
      if (def) {
        activeSchemeId.value = def.id;
        applyScheme(def);
      } else {
        activeSchemeId.value = CUSTOM_SCHEME_VALUE;
        resetFormDefaults();
      }
    }
  } catch {
    schemes.value = [];
  } finally {
    schemesLoading.value = false;
  }
}

function onSchemeSelectChange(value: number) {
  activeSchemeId.value = value;
  if (value === CUSTOM_SCHEME_VALUE) {
    clearSchemeModified();
    resetFormDefaults();
    return;
  }
  const scheme = schemes.value.find((s) => s.id === value);
  if (scheme) {
    applyScheme(scheme);
  }
}

watch(granularity, (g) => {
  if (applyingScheme.value) {
    return;
  }
  selectedKeys.value = getDefaultSelectedKeys(g);
  orderedSelectedKeys.value = buildDefaultOrderedKeys(selectedKeys.value, g);
  fieldOrderCustomized.value = false;
  markSchemeModified();
});

watch(
  [orderNo, storeId, status, deliveryMethod, prescriptionType],
  () => {
    if (applyingScheme.value) {
      return;
    }
    markSchemeModified();
  },
);

watch(
  selectedKeys,
  () => {
    if (applyingScheme.value) {
      return;
    }
    syncOrderFromSelection();
  },
  { deep: true },
);

const loadStores = () => {
  fetchingStores.value = true;
  getStoreOption({})
    .then((res: { id: number; name: string }[]) => {
      storeOptions.value = (res || []).map((item) => ({
        label: `${item.name}【${item.id}】`,
        value: item.id,
      }));
    })
    .finally(() => {
      fetchingStores.value = false;
    });
};

const loadStatusOptions = () => {
  getOrderStatusOption({}).then((res: { id: number; name: string }[]) => {
    statusOptions.value = (res || []).map((item) => ({
      label: item.name,
      value: item.id,
    }));
  });
};

/** 拉取完整订单类型（含非药品、医疗器械等） */
const loadPrescriptionTypeOptions = () => {
  getOrderPrescriptionTypeOption({}).then(
    (res: { id: number; name: string }[]) => {
      prescriptionTypeOptions.value = (res || []).map((item) => ({
        label: item.name,
        value: item.id,
      }));
    },
  );
};

function onSelectedKeysChange() {
  markSchemeModified();
}

function selectAllFields() {
  selectedKeys.value = fieldList.value.map((f) => f.key);
  fieldOrderCustomized.value = false;
  markSchemeModified();
}

function clearAllFields() {
  selectedKeys.value = [];
  orderedSelectedKeys.value = [];
  fieldOrderCustomized.value = false;
  markSchemeModified();
}

function resetDefaultFields() {
  selectedKeys.value = getDefaultSelectedKeys(granularity.value);
  orderedSelectedKeys.value = buildDefaultOrderedKeys(
    selectedKeys.value,
    granularity.value,
  );
  fieldOrderCustomized.value = false;
  markSchemeModified();
}

function toggleGroup(group: string, checked: boolean) {
  const keys = groupedFields.value[group]?.map((f) => f.key) ?? [];
  if (checked) {
    selectedKeys.value = [...new Set([...selectedKeys.value, ...keys])];
  } else {
    selectedKeys.value = selectedKeys.value.filter((k) => !keys.includes(k));
  }
  markSchemeModified();
}

function isGroupAllChecked(group: string): boolean {
  const keys = groupedFields.value[group]?.map((f) => f.key) ?? [];
  return keys.length > 0 && keys.every((k) => selectedKeys.value.includes(k));
}

function popupContainerBody() {
  return document.body;
}

function openFieldSortModal() {
  if (orderedSelectedKeys.value.length === 0) {
    message.warning('请至少选择一个导出字段');
    return;
  }
  sortModalOpen.value = true;
}

function onFieldSortConfirm(keys: string[]) {
  orderedSelectedKeys.value = keys;
  const defaultOrder = buildDefaultOrderedKeys(
    selectedKeys.value,
    granularity.value,
  );
  fieldOrderCustomized.value = keys.join('\0') !== defaultOrder.join('\0');
  markSchemeModified();
}

function openSaveSchemeModal() {
  if (orderedSelectedKeys.value.length === 0) {
    message.warning('请至少选择一个导出字段');
    return;
  }
  saveSchemeName.value = '';
  saveSchemeDefault.value = false;
  saveModalOpen.value = true;
}

async function confirmSaveScheme() {
  const name = saveSchemeName.value.trim();
  if (!name) {
    message.warning('请输入方案名称');
    return;
  }
  saveModalLoading.value = true;
  try {
    const saved = await createOrderExportScheme({
      name,
      is_default: saveSchemeDefault.value ? 1 : 0,
      granularity: granularity.value,
      config: buildSchemeConfigFromForm(formState()),
    });
    message.success('方案已保存');
    await loadSchemes(false);
    activeSchemeId.value = saved.id;
    fieldOrderCustomized.value = true;
    clearSchemeModified();
    saveModalOpen.value = false;
  } catch (e: any) {
    message.error(e?.message || '保存失败');
  } finally {
    saveModalLoading.value = false;
  }
}

async function handleUpdateScheme() {
  if (activeSchemeId.value <= CUSTOM_SCHEME_VALUE || !activeSavedScheme.value) {
    return;
  }
  if (orderedSelectedKeys.value.length === 0) {
    message.warning('请至少选择一个导出字段');
    return;
  }
  const scheme = activeSavedScheme.value;
  AntModal.confirm({
    title: '更新导出方案',
    content: `将当前配置同步至方案「${scheme.name}」，是否继续？`,
    onOk: async () => {
      updateSchemeLoading.value = true;
      try {
        await updateOrderExportScheme({
          id: scheme.id,
          granularity: granularity.value,
          config: buildSchemeConfigFromForm(formState()),
        });
        message.success('方案已更新');
        await loadSchemes(false);
        activeSchemeId.value = scheme.id;
        clearSchemeModified();
      } catch (e: any) {
        message.error(e?.message || '更新失败');
      } finally {
        updateSchemeLoading.value = false;
      }
    },
  });
}

async function toggleSchemeDefault() {
  const scheme = activeSavedScheme.value;
  if (!scheme || defaultTagLoading.value) {
    return;
  }
  const nextDefault = scheme.is_default === 1 ? 0 : 1;
  defaultTagLoading.value = true;
  try {
    await updateOrderExportScheme({
      id: scheme.id,
      is_default: nextDefault,
    });
    message.success(nextDefault === 1 ? '已设为默认方案' : '已取消默认方案');
    await loadSchemes(false);
    activeSchemeId.value = scheme.id;
  } catch (e: any) {
    message.error(e?.message || '操作失败');
  } finally {
    defaultTagLoading.value = false;
  }
}

async function handleDeleteScheme() {
  if (activeSchemeId.value <= CUSTOM_SCHEME_VALUE) {
    return;
  }
  AntModal.confirm({
    title: '删除导出方案',
    content: `确定删除方案「${activeSavedScheme.value?.name ?? ''}」吗？`,
    okType: 'danger',
    onOk: async () => {
      await deleteOrderExportScheme({ id: activeSchemeId.value });
      message.success('已删除');
      activeSchemeId.value = CUSTOM_SCHEME_VALUE;
      clearSchemeModified();
      resetFormDefaults();
      await loadSchemes(true);
    },
  });
}

const [Modal, modalApi] = useVbenModal({
  // 退出全屏后的宽度：两列布局左列固定 400px，弹窗必须足够宽右列才有空间
  class: 'w-[1200px]',
  fullscreen: true,
  fullscreenButton: true,
  draggable: true,
  onCancel() {
    modalApi.close();
  },
  onConfirm: async () => {
    if (!searchTime.value?.[0] || !searchTime.value?.[1]) {
      message.warning('请选择时间范围');
      return;
    }
    if (orderedSelectedKeys.value.length === 0) {
      message.warning('请至少选择一个导出字段');
      return;
    }

    loading.value = true;
    loadingStep.value = '正在拉取数据…';
    try {
      const timeRange = searchTimeRange();
      const params: OrderExportDataParams = {
        search_time: timeRange,
        granularity: granularity.value,
      };
      if (orderNo.value.trim()) {
        params.order_no = orderNo.value.trim();
      }
      if (storeId.value != null) {
        params.store_id = storeId.value;
      }
      if (status.value != null) {
        params.status = status.value;
      }
      if (deliveryMethod.value != null) {
        params.delivery_method = deliveryMethod.value;
      }
      if (prescriptionType.value != null) {
        params.prescription_type = prescriptionType.value;
      }
      if (drugKeyword.value.trim()) {
        params.drug_keyword = drugKeyword.value.trim();
      }
      if (patientKeyword.value.trim()) {
        params.patient_keyword = patientKeyword.value.trim();
      }
      if (doctorKeyword.value.trim()) {
        params.doctor_keyword = doctorKeyword.value.trim();
      }

      const res = await getOrderExportDataApi(params);
      const rows = res?.rows ?? [];
      if (rows.length === 0) {
        message.warning('暂无符合条件的数据');
        return;
      }

      // 订单维度勾选附加工作簿：按同筛选条件再拉一次 item 粒度，用于按订单分组的商品明细 Sheet
      let detailSheet:
        | undefined
        | {
            fieldMeta: ReturnType<typeof getExportFields>;
            rows: Record<string, unknown>[];
            selectedFields: string[];
          };
      if (granularity.value === 'order' && withDetailWorkbook.value) {
        loadingStep.value = '正在拉取商品明细…';
        // 明细工作簿独立容错：明细接口失败只降级为「仅导出订单汇总」，不拖垮整个导出
        try {
          const detailRes = await getOrderExportDataApi({
            ...params,
            granularity: 'item',
          });
          const detailRows = detailRes?.rows ?? [];
          if (detailRows.length > 0) {
            detailSheet = {
              rows: detailRows,
              // 明细工作簿用 item 粒度默认字段集（不提供单独的字段选择，保持交互简单）
              selectedFields: buildDefaultOrderedKeys(
                getDefaultSelectedKeys('item'),
                'item',
              ),
              fieldMeta: getExportFields('item'),
            };
          }
        } catch (detailError) {
          console.error('商品明细拉取失败，仅导出订单汇总:', detailError);
          message.warning('商品明细拉取失败，本次仅导出订单汇总');
        }
      }

      loadingStep.value = '正在生成 Excel…';
      const fieldsMeta = getExportFields(granularity.value);
      const buffer = await exportProductOrderExcel({
        rows,
        selectedFields: orderedSelectedKeys.value,
        fieldMeta: fieldsMeta,
        granularity: granularity.value,
        exportedAt: new Date(),
        detailSheet,
        filters: {
          search_time: timeRange,
          order_no: orderNo.value.trim() || undefined,
          store_name: storeNameOf(storeId.value),
          status_text: labelOf(statusOptions.value, status.value),
          delivery_method_text: labelOf(DELIVERY_OPTIONS, deliveryMethod.value),
          prescription_type_text: labelOf(
            prescriptionTypeOptions.value,
            prescriptionType.value,
          ),
          export_fields_text: selectedFieldLabels(),
          row_count: rows.length,
        },
      });

      downloadByData(
        buffer,
        exportFilename(granularity.value, timeRange),
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      );
      message.success(`导出成功，共 ${rows.length} 条`);
      modalApi.close();
    } catch (e: any) {
      message.error(e?.message || '导出失败');
    } finally {
      loading.value = false;
      loadingStep.value = '';
    }
  },
  onOpenChange(isOpen: boolean) {
    if (isOpen) {
      modalApi.setState({ fullscreen: true });

      const data =
        modalApi.getData<{
          store_export_locked?: boolean;
          locked_store_id?: number;
          locked_store_name?: string;
        }>() || {};

      searchTime.value = [dayjs().startOf('month'), dayjs()];
      activeSchemeId.value = CUSTOM_SCHEME_VALUE;
      clearSchemeModified();
      resetFormDefaults();

      storeExportLocked.value = !!data.store_export_locked;
      if (storeExportLocked.value && data.locked_store_id != null) {
        storeId.value = data.locked_store_id;
        lockedStoreName.value = data.locked_store_name || '本诊所';
      } else {
        storeId.value = undefined;
        lockedStoreName.value = '';
        loadStores();
      }
      loadStatusOptions();
      loadPrescriptionTypeOptions();
      void loadSchemes(true);
    }
  },
});
</script>

<template>
  <Modal
    :confirm-loading="loading"
    :ok-text="loading ? loadingStep || '导出中…' : '导出 Excel'"
    title="导出商品订单"
  >
    <!--
      布局说明：不再用 max-h[calc] 写死高度——矮屏下会把各区块 flex 压缩导致内容互相叠压、
      字段复选框被遮挡无法点选。改为：
      - 小屏（<lg）：自然高度纵向铺开，滚动交给 vben modal body（自带 overflow-y-auto）
      - 宽屏（lg+，全屏弹窗常态）：左右两列，左列「方案/筛选/导出设置」独立滚动，
        右列整块留给「导出字段」内部滚动，字段再多也不会被挤压
    -->
    <div class="flex min-h-0 flex-col gap-4 py-1 lg:h-full lg:flex-row lg:items-stretch">
      <!-- 左列：导出方案 + 筛选条件 + 导出设置 -->
      <div
        class="flex min-h-0 flex-col gap-4 lg:w-[400px] lg:flex-none lg:overflow-y-auto lg:pr-1"
      >
      <!-- 导出方案 -->
      <div>
        <div class="mb-2 text-sm font-medium">导出方案</div>
        <div
          class="flex flex-wrap items-center gap-2 rounded-md border border-border bg-muted/20 p-3"
        >
          <Select
            :value="activeSchemeId"
            class="min-w-[200px] flex-1"
            :loading="schemesLoading"
            :options="schemeSelectOptions"
            placeholder="选择导出方案"
            @change="onSchemeSelectChange"
          />
          <Tag
            v-if="activeSchemeId > CUSTOM_SCHEME_VALUE && activeSavedScheme"
            class="cursor-pointer select-none"
            :color="activeSavedScheme.is_default === 1 ? 'gold' : undefined"
            @click.stop="toggleSchemeDefault"
          >
            {{ defaultTagLoading ? '…' : activeSavedScheme.is_default === 1 ? '默认' : '设为默认' }}
          </Tag>
          <Button
            v-if="activeSchemeId > CUSTOM_SCHEME_VALUE"
            :loading="updateSchemeLoading"
            type="primary"
            @click="handleUpdateScheme"
          >
            更新方案
          </Button>
          <Button type="primary" ghost @click="openSaveSchemeModal">保存方案</Button>
          <Button
            v-if="activeSchemeId > CUSTOM_SCHEME_VALUE"
            danger
            @click="handleDeleteScheme"
          >
            删除方案
          </Button>
        </div>
        <div
          v-if="schemeModified && activeSchemeId > CUSTOM_SCHEME_VALUE"
          class="mt-2 text-xs text-amber-600 dark:text-amber-500"
        >
          当前方案已修改，点击「更新方案」同步保存
        </div>
      </div>

      <!-- 区块 A：筛选条件 -->
      <div>
        <div class="mb-2 text-sm font-medium">筛选条件</div>
        <div
          class="grid grid-cols-2 gap-x-4 gap-y-3 rounded-md border border-border bg-muted/20 p-3"
        >
          <div class="col-span-2">
            <div class="mb-1 text-xs text-muted-foreground">时间范围 *</div>
            <DatePicker.RangePicker
              v-model:value="searchTime"
              class="w-full"
              format="YYYY-MM-DD"
              :get-popup-container="popupContainerBody"
            />
          </div>
          <div>
            <div class="mb-1 text-xs text-muted-foreground">订单号</div>
            <Input v-model:value="orderNo" allow-clear placeholder="输入订单号" />
          </div>
          <div>
            <div class="mb-1 text-xs text-muted-foreground">门店</div>
            <div
              v-if="storeExportLocked"
              class="rounded border bg-background px-3 py-1.5 text-sm"
            >
              {{ lockedStoreName || '本诊所' }}（ID: {{ storeId }}）
            </div>
            <Select
              v-else
              v-model:value="storeId"
              allow-clear
              show-search
              class="w-full"
              :filter-option="
                (input: string, option: any) =>
                  (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
              "
              :loading="fetchingStores"
              :options="storeOptions"
              placeholder="全部"
              option-filter-prop="label"
            />
          </div>
          <div>
            <div class="mb-1 text-xs text-muted-foreground">订单状态</div>
            <Select
              v-model:value="status"
              allow-clear
              class="w-full"
              :options="statusOptions"
              placeholder="全部"
            />
          </div>
          <div>
            <div class="mb-1 text-xs text-muted-foreground">发货方式</div>
            <Select
              v-model:value="deliveryMethod"
              allow-clear
              class="w-full"
              :options="DELIVERY_OPTIONS"
              placeholder="全部"
            />
          </div>
          <div>
            <div class="mb-1 text-xs text-muted-foreground">订单类型</div>
            <Select
              v-model:value="prescriptionType"
              allow-clear
              class="w-full"
              :options="prescriptionTypeOptions"
              placeholder="全部"
            />
          </div>
          <div>
            <div class="mb-1 text-xs text-muted-foreground">药品</div>
            <Input
              v-model:value="drugKeyword"
              allow-clear
              placeholder="药品名称/拼音首拼"
            />
          </div>
          <div>
            <div class="mb-1 text-xs text-muted-foreground">就诊人</div>
            <Input
              v-model:value="patientKeyword"
              allow-clear
              placeholder="姓名/手机号"
            />
          </div>
          <div>
            <div class="mb-1 text-xs text-muted-foreground">医生</div>
            <Input
              v-model:value="doctorKeyword"
              allow-clear
              placeholder="姓名/手机号"
            />
          </div>
        </div>
      </div>

      <!-- 区块 B：导出设置 -->
      <div>
        <div class="mb-2 text-sm font-medium">导出设置</div>
        <Radio.Group v-model:value="granularity">
          <Radio value="order">订单维度（一行一个订单）</Radio>
          <Radio value="item">商品明细维度（一行一个商品）</Radio>
        </Radio.Group>
        <div v-if="granularity === 'order'" class="mt-2">
          <Checkbox v-model:checked="withDetailWorkbook">
            附加「订单商品明细」工作簿（按订单分组导出每单商品清单）
          </Checkbox>
        </div>
        <div class="mt-1 text-xs text-muted-foreground">
          当前粒度：{{ granularityLabel(granularity) }}，导出文件将包含筛选条件说明与专业表头样式
        </div>
      </div>
      </div>

      <!-- 区块 C：导出字段（右列，宽屏下独占一列内部滚动） -->
      <div class="flex min-h-0 flex-1 flex-col">
        <div class="mb-2 flex flex-wrap items-center justify-between gap-2">
          <span class="text-sm font-medium">导出字段</span>
          <Space size="small" wrap>
            <span class="text-xs text-muted-foreground">
              已选 {{ selectedCount }} / {{ totalFieldCount }}
            </span>
            <Button
              size="small"
              type="link"
              :disabled="orderedSelectedKeys.length === 0"
              @click="openFieldSortModal"
            >
              字段排序
            </Button>
            <Button size="small" type="link" @click="selectAllFields">全选</Button>
            <Button size="small" type="link" @click="clearAllFields">取消全选</Button>
            <Button size="small" type="link" @click="resetDefaultFields">恢复默认</Button>
          </Space>
        </div>

        <Checkbox.Group
          v-model:value="selectedKeys"
          class="min-h-0 flex-1 overflow-y-auto rounded-md border border-border p-3"
          @change="onSelectedKeysChange"
        >
          <div
            v-for="(fields, group) in groupedFields"
            :key="group"
            class="mb-3 last:mb-0"
          >
            <div class="mb-1.5 flex items-center gap-2">
              <Checkbox
                :checked="isGroupAllChecked(group)"
                @change="(e: any) => toggleGroup(group, e.target.checked)"
              >
                <span class="text-xs font-medium text-muted-foreground">{{ group }}</span>
              </Checkbox>
            </div>
            <!-- 列数随右列宽度自适应：宽屏铺开减少纵向滚动，窄屏两列保证可点面积 -->
            <div class="grid grid-cols-2 gap-x-2 gap-y-1.5 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
              <Checkbox v-for="field in fields" :key="field.key" :value="field.key">
                <span class="text-sm">{{ field.label }}</span>
              </Checkbox>
            </div>
          </div>
        </Checkbox.Group>

        <div
          v-if="fieldOrderPreview"
          class="mt-2 max-h-24 flex-none overflow-y-auto rounded-md border border-dashed border-border bg-muted/10 px-3 py-2 text-xs leading-relaxed text-muted-foreground"
        >
          <span class="font-medium text-foreground">导出列顺序：</span>
          {{ fieldOrderPreview }}
        </div>
      </div>
    </div>

    <ProductOrderExportFieldSortModal
      v-model:open="sortModalOpen"
      :field-meta="fieldList"
      :granularity="granularity"
      :ordered-keys="orderedSelectedKeys"
      :selected-keys="selectedKeys"
      @confirm="onFieldSortConfirm"
    />

    <AntModal
      v-model:open="saveModalOpen"
      :confirm-loading="saveModalLoading"
      title="保存导出方案"
      ok-text="保存"
      @ok="confirmSaveScheme"
    >
      <div class="flex flex-col gap-3 py-2">
        <div>
          <div class="mb-1 text-sm text-muted-foreground">方案名称</div>
          <Input v-model:value="saveSchemeName" allow-clear placeholder="请输入方案名称" />
        </div>
        <Checkbox v-model:checked="saveSchemeDefault">设为默认方案（打开弹窗时自动套用）</Checkbox>
      </div>
    </AntModal>
  </Modal>
</template>
