<template>
  <section class="page-grid">
    <div v-if="feedbackMessage" class="feedback-banner">{{ feedbackMessage }}</div>
    <div v-if="errorMessage" class="feedback-banner error-banner">{{ errorMessage }}</div>

    <section v-if="showCustomerSection" class="panel">
      <div class="page-hero-card sales-chain-hero sales-planning-hero">
        <div class="page-hero-copy">
          <p class="eyebrow">客户名录</p>
          <h3>客户基础信息</h3>
          <p class="page-hero-subtitle">维护客户主档、联系人与送货地址，让销售订单抬头信息保持一致。</p>
        </div>
        <div class="page-hero-actions supplier-action-bar">
          <button class="supplier-action-button supplier-action-primary no-auto-icon" type="button" @click="openCustomerDrawer">
            <span class="supplier-action-icon supplier-action-icon-add" aria-hidden="true">+</span>
            <span>新增客户</span>
          </button>
          <div class="supplier-exchange-group" aria-label="客户名录导入导出">
            <button class="supplier-action-button supplier-action-import no-auto-icon" type="button" :disabled="customerImporting" @click="triggerCustomerImport">
              <span class="supplier-action-icon" aria-hidden="true">
                <svg viewBox="0 0 24 24">
                  <path d="M12 21V9" />
                  <path d="m7 16 5 5 5-5" />
                  <path d="M5 8V5h14v3" />
                </svg>
              </span>
              <span>{{ customerImporting ? "导入中..." : "导入" }}</span>
            </button>
            <button class="supplier-action-button supplier-action-export no-auto-icon" type="button" :disabled="customerExporting" @click="exportCustomers">
              <span class="supplier-action-icon" aria-hidden="true">
                <svg viewBox="0 0 24 24">
                  <path d="M12 3v12" />
                  <path d="m7 8 5-5 5 5" />
                  <path d="M5 16v3h14v-3" />
                </svg>
              </span>
              <span>{{ customerExporting ? "导出中..." : "导出" }}</span>
            </button>
          </div>
          <input ref="customerImportInputRef" class="hidden-file-input" type="file" accept=".xlsx,.xlsm" @change="importCustomers" />
        </div>
      </div>

      <TableControls
        v-model:search="customerControls.search.value"
        v-model:sort-key="customerControls.sortKey.value"
        v-model:sort-direction="customerControls.sortDirection.value"
        :sort-options="customerControls.sortOptions"
        placeholder="搜索客户名称、客户编码、联系人、电话"
      />

      <div class="customer-info-list">
        <article v-for="customer in paginatedCustomers" :key="customer.id" class="customer-info-card">
          <div>
            <strong>{{ customer.customer_name }}</strong>
            <p>{{ customer.customer_code }} · {{ customer.short_name || "未维护简称" }}</p>
          </div>
          <div>
            <span>联系人</span>
            <strong>{{ formatContactNames(customer) }}</strong>
          </div>
          <div>
            <span>联系电话</span>
            <strong>{{ formatContactPhones(customer) }}</strong>
          </div>
          <div>
            <span>送货地址</span>
            <strong>{{ customer.address || "-" }}</strong>
          </div>
          <div class="action-row">
            <button class="ghost-button" type="button" @click="openCustomerEditDrawer(customer)">编辑</button>
          </div>
        </article>
        <div v-if="!filteredCustomers.length" class="workflow-empty-card">暂无客户资料，请点击右上角新增客户。</div>
      </div>
      <PaginationBar v-model:page="customerPage" v-model:page-size="customerPageSize" :total="filteredCustomers.length" />
    </section>

    <section v-if="showOrderSection" class="panel">
      <div class="page-hero-card sales-chain-hero sales-order-hero">
        <div class="page-hero-copy">
          <p class="eyebrow">销售订单</p>
          <h3>销售订单与发货追溯</h3>
          <p class="page-hero-subtitle">集中查看订单数量、交期、金额和发货批次，保持接单到交付口径一致。</p>
        </div>
        <div class="page-hero-actions">
          <button
            class="contract-header-button"
            type="button"
            :disabled="!selectedOrderIds.length"
            title="勾选销售订单后生成基础销售合同"
            @click="generateSalesContract"
          >
            生成合同
          </button>
          <button
            class="contract-header-button"
            type="button"
            title="勾选销售订单后批量下载PDF归档"
            @click="batchDownloadSalesArchives"
          >
            批量下载PDF归档
          </button>
          <button class="primary-button" type="button" @click="openSalesOrderDrawer">新增销售订单</button>
        </div>
      </div>

      <TableControls
        v-model:search="orderControls.search.value"
        v-model:sort-key="orderControls.sortKey.value"
        v-model:sort-direction="orderControls.sortDirection.value"
        :sort-options="orderControls.sortOptions"
        placeholder="搜索销售订单号、客户、产品、发货批次、库存批次号、状态"
      />

      <div class="table-wrap">
        <table class="data-table">
          <thead>
            <tr>
              <th class="select-col">
                <input
                  type="checkbox"
                  :checked="allVisibleOrdersSelected"
                  :indeterminate="someVisibleOrdersSelected && !allVisibleOrdersSelected"
                  title="选择当前页销售订单"
                  @change="toggleVisibleOrders"
                />
              </th>
              <th>销售订单号</th>
              <th>客户</th>
              <th>销售人员</th>
              <th>产品</th>
              <th>下单日期</th>
              <th>交期</th>
              <th>订单数量</th>
              <th>已发数量</th>
              <th>未发数量</th>
              <th>发货批次追踪</th>
              <th>订单金额</th>
              <th>状态</th>
              <th class="sales-archive-col">归档</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="order in paginatedOrders"
              :key="order.order_id"
              :class="{ 'row-selected': selectedOrderId === order.order_id }"
            >
              <td class="select-col">
                <input
                  type="checkbox"
                  :checked="selectedOrderIdSet.has(Number(order.order_id))"
                  title="选择生成销售合同"
                  @change="toggleOrderSelection(order.order_id)"
                />
              </td>
              <td>
                <button class="link-button" type="button" @click="openSalesOrderDetailDrawer(order)">
                  {{ order.order_no }}
                </button>
              </td>
              <td>{{ order.customer_name || "-" }}</td>
              <td>{{ order.sales_employee_name || "-" }}</td>
              <td>{{ order.product_names || "-" }}</td>
              <td>{{ formatDate(order.order_date) }}</td>
              <td>{{ formatDate(order.promised_date) }}</td>
              <td>{{ formatQty(order.total_order_qty) }}</td>
              <td>{{ formatQty(order.total_delivered_qty) }}</td>
              <td>{{ formatQty(order.total_pending_qty) }}</td>
              <td class="trace-cell" :title="order.delivery_trace_full || ''">{{ order.delivery_trace || "未发货" }}</td>
              <td>¥{{ formatAmount(order.total_amount) }}</td>
              <td>
                <StatusBadge :value="order.display_status || order.status" :text="formatStatusLabel(order.display_status || order.status)" />
              </td>
              <td class="sales-archive-cell">
                <div class="sales-archive-actions-compact">
                  <DocumentArchiveActions
                    :status="order.archive_status"
                    @preview="previewDocumentArchive('sales-order', order.order_id)"
                    @download="downloadDocumentArchive('sales-order', order.order_id, `${order.order_no || '销售订单'}归档.pdf`)"
                    @regenerate="regenerateDocumentArchive('sales-order', order.order_id)"
                  />
                </div>
              </td>
              <td class="action-row">
                <button
                  class="ghost-button danger-ghost table-action-button"
                  type="button"
                  :disabled="!canDeleteSalesOrder(order)"
                  :title="deleteSalesOrderTitle(order)"
                  @click="deleteSalesOrderRow(order)"
                >
                  删除
                </button>
              </td>
            </tr>
            <tr v-if="!filteredOrders.length">
              <td colspan="15" class="empty-row">暂无销售订单，请点击右上角新增销售订单。</td>
            </tr>
          </tbody>
        </table>
      </div>
      <PaginationBar v-model:page="orderPage" v-model:page-size="orderPageSize" :total="filteredOrders.length" />
    </section>

    <FormDrawer
      :open="customerDrawerOpen"
      eyebrow="客户名录"
      :title="editingCustomerId ? '编辑客户' : '新增客户'"
      tag="客户主档"
      @close="closeCustomerDrawer"
    >
      <form class="stack-form" @submit.prevent="submitCustomer">
        <FormSection title="客户档案" columns="1">
          <div class="double-field">
            <label class="form-field">
              <span>客户名称</span>
              <input v-model.trim="customerForm.customer_name" type="text" required />
            </label>
            <label class="form-field">
              <span>客户简称</span>
              <input v-model.trim="customerForm.short_name" type="text" />
            </label>
          </div>
        </FormSection>

        <FormSection title="联系人" columns="1">
          <template #actions>
            <FieldHint text="最多维护3位联系人，保存后用于客户名录展示和销售订单追溯。" />
            <button class="ghost-button" type="button" :disabled="customerForm.contacts.length >= 3" @click="addCustomerContact">添加联系人</button>
          </template>
          <div v-for="(contact, index) in customerForm.contacts" :key="`customer-contact-${index}`" class="triple-field">
            <label class="form-field">
              <span>联系人{{ index + 1 }}</span>
              <input v-model.trim="contact.contact_name" type="text" />
            </label>
            <label class="form-field">
              <span>联系电话{{ index + 1 }}</span>
              <input v-model.trim="contact.contact_phone" type="text" />
            </label>
            <div class="form-field form-field-action">
              <span>&nbsp;</span>
              <button class="ghost-button danger-ghost" type="button" @click="removeCustomerContact(index)">
                {{ customerForm.contacts.length > 1 ? "删除" : "清空" }}
              </button>
            </div>
          </div>
        </FormSection>

        <FormSection title="交付与账期" columns="1">
          <div class="double-field">
            <label class="form-field">
              <span>送货地址</span>
              <input v-model.trim="customerForm.address" type="text" />
            </label>
            <label class="form-field">
              <span>账期(天)</span>
              <input v-model.number="customerForm.credit_days" type="number" min="0" />
            </label>
          </div>
        </FormSection>

        <div class="drawer-form-actions">
          <button class="primary-button" type="submit" :disabled="customerSubmitting">
            {{ customerSubmitting ? "保存中..." : editingCustomerId ? "更新客户" : "新增客户" }}
          </button>
        </div>
      </form>
    </FormDrawer>

    <FormDrawer
      :open="salesOrderDrawerOpen"
      eyebrow="销售订单"
      title="新增销售订单"
      tag="接单建档"
      wide
      @close="salesOrderDrawerOpen = false"
    >
      <form class="stack-form" @submit.prevent="submitSalesOrder">
        <DocumentPaper
          title="销售订单"
          :document-no="salesOrderNoPreview"
          :signature-labels="['销售确认', '客户确认', '财务复核', '制单人']"
          tone="red"
        >
          <DocumentGrid :fields="salesDocumentHeaderFields" columns="3">
            <template #customer>
              <select v-model.number="salesOrderForm.customer_id" required @change="applySalesCustomerDefaults">
                <option disabled value="">请选择客户</option>
                <option v-for="customer in customers" :key="customer.id" :value="customer.id">
                  {{ customer.customer_name }}
                </option>
              </select>
            </template>
            <template #sales_employee>
              <select v-model.number="salesOrderForm.sales_employee_id" required>
                <option disabled value="">请选择销售人员</option>
                <option v-for="employee in salesEmployeeOptions" :key="employee.employee_id" :value="employee.employee_id">
                  {{ employeeOptionLabel(employee) }}
                </option>
              </select>
            </template>
            <template #promised_date>
              <input v-model="salesOrderForm.promised_date" type="date" />
            </template>
            <template #tax_rate>
              <input v-model.number="salesOrderForm.tax_rate" type="number" min="0" step="0.0001" />
            </template>
            <template #delivery_address>
              <input v-model.trim="salesOrderForm.delivery_address" type="text" />
            </template>
            <template #remark>
              <textarea v-model.trim="salesOrderForm.remark" rows="2"></textarea>
            </template>
          </DocumentGrid>

          <div class="document-form-hint-row">
            <FieldHint text="选择客户后会自动带出送货地址，仍可按本单实际交付地址调整。" />
          </div>

          <DocumentLineTable title="订单明细" :columns="salesDocumentLineColumns">
            <template #actions>
              <button class="ghost-button" type="button" @click="addSalesOrderItem">增加一行</button>
            </template>
            <tr v-for="(item, index) in salesOrderForm.items" :key="item.row_uid">
              <td class="document-line-index">{{ index + 1 }}</td>
              <td>
                <select v-model.number="item.product_item_id" required>
                  <option disabled value="">请选择产品</option>
                  <option v-for="product in products" :key="product.item_id" :value="product.item_id">
                    {{ product.item_code }} · {{ product.item_name }} · {{ product.version_no }}
                  </option>
                </select>
              </td>
              <td>
                <input v-model.number="item.order_qty" type="number" min="0.001" step="0.001" required />
              </td>
              <td>
                <input v-model.number="item.unit_price" type="number" min="0" step="0.0001" />
              </td>
              <td>
                <input v-model.trim="item.customer_part_no" type="text" />
              </td>
              <td>
                <input v-model="item.promised_date" type="date" @input="markSalesOrderItemPromisedDateTouched(item)" />
              </td>
              <td>
                <button
                  v-if="salesOrderForm.items.length > 1"
                  class="ghost-button danger-ghost table-action-button"
                  type="button"
                  @click="removeSalesOrderItem(index)"
                >
                  删除
                </button>
              </td>
            </tr>
          </DocumentLineTable>
        </DocumentPaper>

        <div class="drawer-form-actions">
          <button class="primary-button" type="submit" :disabled="salesOrderSubmitting">
            {{ salesOrderSubmitting ? "保存并归档中..." : "保存并生成PDF归档" }}
          </button>
        </div>
      </form>
    </FormDrawer>

    <FormDrawer
      :open="orderDetailDrawerOpen"
      eyebrow="销售订单明细"
      :title="activeOrder ? activeOrder.order_no : '销售订单明细'"
      tag="发货与批次追溯"
      wide
      @close="orderDetailDrawerOpen = false"
    >
      <div v-if="activeOrder" class="detail-grid">
        <div class="detail-item">
          <span>客户</span>
          <strong>{{ activeOrder.customer_name }}</strong>
        </div>
        <div class="detail-item">
          <span>订单数量</span>
          <strong>{{ formatQty(activeOrder.total_order_qty) }}</strong>
        </div>
        <div class="detail-item">
          <span>已发数量</span>
          <strong>{{ formatQty(activeOrder.total_delivered_qty) }}</strong>
        </div>
        <div class="detail-item">
          <span>未发数量</span>
          <strong>{{ formatQty(activeOrder.total_pending_qty) }}</strong>
        </div>
      </div>

      <div class="subsection-head">
        <strong>订单明细</strong>
      </div>
      <div class="table-wrap">
        <table class="data-table compact-table">
          <thead>
            <tr>
              <th>产品</th>
              <th>客户料号</th>
              <th>订单数量</th>
              <th>已发数量</th>
              <th>未发数量</th>
              <th>单价</th>
              <th>金额</th>
              <th>状态</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="item in activeOrderItems" :key="item.sales_order_item_id">
              <td>{{ item.product_code }} · {{ item.product_name }}</td>
              <td>{{ item.customer_part_no || "-" }}</td>
              <td>{{ formatQty(item.order_qty) }}</td>
              <td>{{ formatQty(item.delivered_qty) }}</td>
              <td>{{ formatQty(orderItemPendingQty(item)) }}</td>
              <td>¥{{ formatAmount(item.unit_price) }}</td>
              <td>¥{{ formatAmount(item.line_amount) }}</td>
              <td>
                <StatusBadge :value="item.display_status || item.status" :text="formatStatusLabel(item.display_status || item.status)" />
              </td>
            </tr>
            <tr v-if="!activeOrderItems.length">
              <td colspan="8" class="empty-row">当前销售订单暂无明细</td>
            </tr>
          </tbody>
        </table>
      </div>

      <div class="subsection-head">
        <strong>发货追溯</strong>
      </div>
      <TableControls
        v-model:search="traceControls.search.value"
        v-model:sort-key="traceControls.sortKey.value"
        v-model:sort-direction="traceControls.sortDirection.value"
        :sort-options="traceControls.sortOptions"
        placeholder="搜索发货单、产品、原材料、库存批次号、生产批次"
      />
      <div class="table-wrap">
        <table class="data-table compact-table">
          <thead>
            <tr>
              <th>发货单号</th>
              <th>发货时间</th>
              <th>产品</th>
              <th>原材料</th>
              <th>来源库存批次号</th>
              <th>生产批次</th>
              <th>发货数量</th>
              <th>发货重量</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="item in paginatedTraceItems" :key="item.delivery_item_id">
              <td>{{ item.delivery_no }}</td>
              <td>{{ formatDateTime(item.delivery_date) }}</td>
              <td>{{ item.product_code }} · {{ item.product_name }}</td>
              <td>{{ formatSourceMaterial(item) }}</td>
              <td>{{ sourceInventoryLotNo(item) }}</td>
              <td>{{ item.lot_no || "-" }}</td>
              <td>{{ formatQty(item.delivery_qty) }}</td>
              <td>{{ formatWeight(item.delivery_weight_kg) }}</td>
            </tr>
            <tr v-if="!filteredTraceItems.length">
              <td colspan="8" class="empty-row">当前销售订单暂无发货记录</td>
            </tr>
          </tbody>
        </table>
      </div>
      <PaginationBar v-model:page="tracePage" v-model:page-size="tracePageSize" :total="filteredTraceItems.length" />
    </FormDrawer>
  </section>
</template>

<script setup>
import { computed, onMounted, reactive, ref, watch } from "vue";
import { useRoute } from "vue-router";

import FieldHint from "../components/FieldHint.vue";
import DocumentArchiveActions from "../components/documentForms/DocumentArchiveActions.vue";
import DocumentGrid from "../components/documentForms/DocumentGrid.vue";
import DocumentLineTable from "../components/documentForms/DocumentLineTable.vue";
import DocumentPaper from "../components/documentForms/DocumentPaper.vue";
import FormDrawer from "../components/FormDrawer.vue";
import FormSection from "../components/FormSection.vue";
import PaginationBar from "../components/PaginationBar.vue";
import StatusBadge from "../components/StatusBadge.vue";
import TableControls from "../components/TableControls.vue";
import {
  deleteResource,
  downloadResource,
  fetchResource,
  openResource,
  postDownloadResource,
  postResource,
  putResource,
  uploadResource
} from "../services/api";
import {
  PERSONNEL_PERMISSION_CODES,
  defaultEmployeeIdFromSession,
  employeeOptionLabel,
  fetchPermissionEmployeeOptions
} from "../services/employeeOptions";
import { formatStatusLabel } from "../utils/dictionaries";
import { formatAmount, formatDate, formatDateTime, formatQty, formatWeight } from "../utils/formatters";
import { usePagination } from "../utils/pagination";
import { useTableControls } from "../utils/tableControls";

const route = useRoute();
const customers = ref([]);
const products = ref([]);
const salesEmployeeOptions = ref([]);
const salesOrders = ref([]);
const salesOrderItems = ref([]);
const deliveries = ref([]);
const deliveryItems = ref([]);
const selectedOrderId = ref(null);
const selectedOrderIds = ref([]);
const feedbackMessage = ref("");
const errorMessage = ref("");
const customerSubmitting = ref(false);
const customerImporting = ref(false);
const customerExporting = ref(false);
const customerImportInputRef = ref(null);
const salesOrderSubmitting = ref(false);
const customerDrawerOpen = ref(false);
const editingCustomerId = ref(null);
const salesOrderDrawerOpen = ref(false);
const orderDetailDrawerOpen = ref(false);
let salesOrderItemSerial = 1;

const customerForm = reactive(buildEmptyCustomerForm());
const salesOrderForm = reactive(buildEmptySalesOrderForm());

const salesDocumentLineColumns = [
  { key: "index", label: "序号", width: "64px", class: "document-line-index" },
  { key: "product", label: "产品", width: "28%" },
  { key: "order_qty", label: "订单数量", width: "14%" },
  { key: "unit_price", label: "销售单价", width: "14%" },
  { key: "customer_part_no", label: "客户料号", width: "16%" },
  { key: "promised_date", label: "明细交期", width: "15%" },
  { key: "actions", label: "操作", width: "90px" }
];

const showCustomerSection = computed(
  () => ["sales-planning", "customer-management"].includes(String(route.name || "")) || String(route.query.tab || "") === "customer-management"
);
const showOrderSection = computed(() => ["sales-planning", "order-list"].includes(String(route.name || "")));
const deliveryById = computed(() => new Map(deliveries.value.map((delivery) => [Number(delivery.delivery_id), delivery])));
const orderItemIdsByOrderId = computed(() => {
  const map = new Map();
  salesOrderItems.value.forEach((item) => {
    const orderId = Number(item.sales_order_id);
    if (!map.has(orderId)) {
      map.set(orderId, new Set());
    }
    map.get(orderId).add(Number(item.sales_order_item_id));
  });
  return map;
});
const orderRows = computed(() =>
  salesOrders.value.map((order) => {
    const items = getOrderItems(order.order_id);
    const traces = getOrderDeliveryTrace(order.order_id);
    const totalOrderQty = items.reduce((total, item) => total + Number(item.order_qty || 0), 0);
    const totalDeliveredQty = items.reduce((total, item) => total + Number(item.delivered_qty || 0), 0);
    const traceTexts = traces.map((item) => formatTraceSummary(item));
    return {
      ...order,
      product_names: joinUniqueNames(items.map((item) => item.product_name)),
      total_order_qty: totalOrderQty,
      total_delivered_qty: totalDeliveredQty,
      total_pending_qty: Math.max(totalOrderQty - totalDeliveredQty, 0),
      delivery_trace: summarizeTrace(traceTexts),
      delivery_trace_full: traceTexts.join("；")
    };
  })
);
const salesOrderNoPreview = computed(() => buildNextSalesOrderNo(salesOrders.value));
const activeOrder = computed(() => orderRows.value.find((order) => Number(order.order_id) === Number(selectedOrderId.value)) || null);
const activeOrderItems = computed(() => getOrderItems(selectedOrderId.value));
const traceRows = computed(() => getOrderDeliveryTrace(selectedOrderId.value));
const selectedOrderIdSet = computed(() => new Set(selectedOrderIds.value.map((id) => Number(id))));
const visibleOrderIds = computed(() => paginatedOrders.value.map((order) => Number(order.order_id)));
const allVisibleOrdersSelected = computed(
  () => visibleOrderIds.value.length > 0 && visibleOrderIds.value.every((orderId) => selectedOrderIdSet.value.has(orderId))
);
const someVisibleOrdersSelected = computed(() => visibleOrderIds.value.some((orderId) => selectedOrderIdSet.value.has(orderId)));
const salesDocumentHeaderFields = computed(() => [
  { key: "customer", label: "客户", value: salesOrderForm.customer_id || "" },
  { key: "sales_employee", label: "销售人员", value: salesOrderForm.sales_employee_id || "" },
  { key: "promised_date", label: "交期", value: salesOrderForm.promised_date || "" },
  { key: "tax_rate", label: "税率", value: salesOrderForm.tax_rate },
  { key: "delivery_address", label: "送货地址", value: salesOrderForm.delivery_address || "-", class: "document-grid-cell-wide" },
  { key: "remark", label: "备注", value: salesOrderForm.remark || "-", class: "document-grid-cell-wide" }
]);

watch(
  () => salesOrderForm.promised_date,
  () => syncSalesOrderItemPromisedDatesFromHeader()
);

const customerControls = useTableControls(customers, {
  searchFields: ["customer_code", "customer_name", "short_name", "contacts", "contact_name", "contact_phone", "address"],
  sortOptions: [
    { key: "customer_code", label: "客户编码" },
    { key: "customer_name", label: "客户名称" },
    { key: "contact_name", label: "联系人" }
  ],
  defaultSortKey: "customer_code",
  defaultSortDirection: "desc"
});
const filteredCustomers = customerControls.rows;
const orderControls = useTableControls(orderRows, {
  searchFields: ["order_no", "customer_name", "product_names", "delivery_trace", "delivery_trace_full", "status"],
  sortOptions: [
    { key: "order_no", label: "销售订单号" },
    { key: "customer_name", label: "客户" },
    { key: "product_names", label: "产品" },
    { key: "order_date", label: "下单日期" },
    { key: "promised_date", label: "交期" },
    { key: "total_order_qty", label: "订单数量" },
    { key: "total_delivered_qty", label: "已发数量" },
    { key: "total_pending_qty", label: "未发数量" },
    { key: "total_amount", label: "订单金额" },
    { key: "status", label: "状态" }
  ],
  defaultSortKey: "order_date",
  defaultSortDirection: "desc"
});
const filteredOrders = orderControls.rows;
const traceControls = useTableControls(traceRows, {
  searchFields: [
    "delivery_no",
    "product_code",
    "product_name",
    "lot_no",
    "source_material_lot_no",
    "source_material_code",
    "source_material_name",
    "source_material_sub_batch_no",
    "source_material_summary"
  ],
  sortOptions: [
    { key: "delivery_no", label: "发货单号" },
    { key: "delivery_date", label: "发货时间" },
    { key: "product_name", label: "产品" },
    { key: "source_material_lot_no", label: "来源库存批次号", field: (row) => sourceInventoryLotNo(row) },
    { key: "lot_no", label: "生产批次" },
    { key: "delivery_qty", label: "发货数量" }
  ],
  defaultSortKey: "delivery_date",
  defaultSortDirection: "desc"
});
const filteredTraceItems = traceControls.rows;
const {
  page: customerPage,
  pageSize: customerPageSize,
  rows: paginatedCustomers
} = usePagination(filteredCustomers);
const {
  page: orderPage,
  pageSize: orderPageSize,
  rows: paginatedOrders
} = usePagination(filteredOrders);
const {
  page: tracePage,
  pageSize: tracePageSize,
  rows: paginatedTraceItems
} = usePagination(filteredTraceItems);

function buildEmptyCustomerForm() {
  return {
    customer_name: "",
    short_name: "",
    contacts: [buildEmptyContact()],
    address: "",
    credit_days: 30
  };
}

function buildEmptyContact() {
  return {
    contact_name: "",
    contact_phone: ""
  };
}

function buildSalesOrderItemRow(promisedDate = "") {
  return {
    row_uid: `sales-order-item-${salesOrderItemSerial++}`,
    product_item_id: "",
    order_qty: 0,
    unit_price: 0,
    promised_date: promisedDate || "",
    promised_date_touched: false,
    customer_part_no: ""
  };
}

function buildEmptySalesOrderForm() {
  return {
    customer_id: "",
    sales_employee_id: "",
    promised_date: "",
    delivery_address: "",
    tax_rate: 0,
    remark: "",
    items: [buildSalesOrderItemRow()]
  };
}

function buildNextSalesOrderNo(orders) {
  const year = String(new Date().getFullYear());
  const prefix = `销售${year}`;
  let maxNo = 0;
  (orders || []).forEach((order) => {
    const match = String(order?.order_no || "").trim().match(new RegExp(`^${prefix}-(\\d{5})$`));
    if (match) {
      maxNo = Math.max(maxNo, Number(match[1]));
    }
  });
  return `${prefix}-${String(maxNo + 1).padStart(5, "0")}`;
}

function joinUniqueNames(names) {
  const values = names.map((name) => String(name || "").trim()).filter(Boolean);
  return Array.from(new Set(values)).join("、");
}

function getOrderItems(orderId) {
  return salesOrderItems.value.filter((item) => Number(item.sales_order_id) === Number(orderId));
}

function getOrderDeliveryTrace(orderId) {
  const itemIds = orderItemIdsByOrderId.value.get(Number(orderId)) || new Set();
  return deliveryItems.value
    .filter((item) => itemIds.has(Number(item.sales_order_item_id)))
    .map((item) => ({
      ...item,
      delivery_date: deliveryById.value.get(Number(item.delivery_id))?.delivery_date || null
    }));
}

function getCustomer(customerId) {
  return customers.value.find((item) => Number(item.id) === Number(customerId)) || null;
}

function orderItemPendingQty(item) {
  return Math.max(Number(item.order_qty || 0) - Number(item.delivered_qty || 0), 0);
}

function formatSourceMaterial(item) {
  const codeName = [item.source_material_code, item.source_material_name].filter(Boolean).join(" · ");
  return codeName || item.source_material_summary || "-";
}

function sourceInventoryLotNo(item) {
  return item?.source_material_lot_no || item?.source_material_sub_batch_no || "-";
}

function formatTraceSummary(item) {
  const material = sourceInventoryLotNo(item) || "未记录库存批次号";
  const productionLot = item.lot_no || "未记录生产批次";
  return `${item.delivery_no}：${item.product_name} ${formatQty(item.delivery_qty)}件 / ${material} / ${productionLot}`;
}

function summarizeTrace(traceTexts) {
  if (!traceTexts.length) {
    return "";
  }
  const head = traceTexts.slice(0, 2).join("；");
  return traceTexts.length > 2 ? `${head}；等${traceTexts.length}批` : head;
}

function toggleOrderSelection(orderId) {
  const normalizedId = Number(orderId);
  if (selectedOrderIdSet.value.has(normalizedId)) {
    selectedOrderIds.value = selectedOrderIds.value.filter((id) => Number(id) !== normalizedId);
    return;
  }
  selectedOrderIds.value = [...selectedOrderIds.value, normalizedId];
}

function toggleVisibleOrders() {
  if (allVisibleOrdersSelected.value) {
    selectedOrderIds.value = selectedOrderIds.value.filter((id) => !visibleOrderIds.value.includes(Number(id)));
    return;
  }
  selectedOrderIds.value = Array.from(new Set([...selectedOrderIds.value, ...visibleOrderIds.value].map((id) => Number(id))));
}

function escapeHtml(value) {
  return String(value ?? "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

function normalizeContractText(value, fallback = "-") {
  const text = String(value ?? "").trim();
  return text || fallback;
}

function formatContractDate(value) {
  const formatted = formatDate(value);
  return formatted === "-" ? "" : formatted;
}

function currentDateText() {
  const now = new Date();
  const pad = (value) => String(value).padStart(2, "0");
  return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
}

function currentTimestampText() {
  const now = new Date();
  const pad = (value) => String(value).padStart(2, "0");
  return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
}

function selectedContractOrders() {
  const selectedSet = selectedOrderIdSet.value;
  return orderRows.value.filter((order) => selectedSet.has(Number(order.order_id)));
}

function buildContractNo(orders) {
  const firstOrderNo = String(orders[0]?.order_no || "SO").replace(/[^a-zA-Z0-9]/g, "").slice(-8) || "SO";
  return `JH-SC-${currentTimestampText()}-${firstOrderNo}`;
}

function buildContractLineRows(orders) {
  return orders.flatMap((order) =>
    getOrderItems(order.order_id).map((item) => ({
      order_no: order.order_no,
      product_code: item.product_code,
      product_name: item.product_name,
      customer_part_no: item.customer_part_no,
      order_qty: Number(item.order_qty || 0),
      unit_price: Number(item.unit_price || 0),
      line_amount: Number(item.line_amount || 0),
      promised_date: item.promised_date || order.promised_date,
      status: item.status
    }))
  );
}

function buildTraceRows(orders) {
  return orders.flatMap((order) =>
    getOrderDeliveryTrace(order.order_id).map((item) => ({
      order_no: order.order_no,
      delivery_no: item.delivery_no,
      delivery_date: item.delivery_date,
      product_name: item.product_name,
      source_material: formatSourceMaterial(item),
      source_material_lot_no: item.source_material_lot_no,
      source_material_sub_batch_no: item.source_material_sub_batch_no,
      source_inventory_lot_no: sourceInventoryLotNo(item),
      lot_no: item.lot_no,
      delivery_qty: item.delivery_qty,
      delivery_weight_kg: item.delivery_weight_kg
    }))
  );
}

function renderContractHtml(orders) {
  const customer = getCustomer(orders[0].customer_id);
  const lines = buildContractLineRows(orders);
  const traces = buildTraceRows(orders);
  const totalAmount = lines.reduce((total, item) => total + Number(item.line_amount || 0), 0);
  const totalQty = lines.reduce((total, item) => total + Number(item.order_qty || 0), 0);
  const contractNo = buildContractNo(orders);
  const orderNos = orders.map((order) => order.order_no).join("、");
  const deliveryAddress = orders.find((order) => order.delivery_address)?.delivery_address || customer?.address || "";
  const promisedDates = Array.from(new Set(orders.map((order) => formatContractDate(order.promised_date)).filter(Boolean))).join("、");
  const lineRowsHtml = lines
    .map(
      (item, index) => `
        <tr>
          <td>${index + 1}</td>
          <td>${escapeHtml(item.order_no)}</td>
          <td>${escapeHtml(item.product_code || "-")}</td>
          <td>${escapeHtml(item.product_name || "-")}</td>
          <td>${escapeHtml(item.customer_part_no || "-")}</td>
          <td class="number">${escapeHtml(formatQty(item.order_qty))}</td>
          <td class="number">¥${escapeHtml(formatAmount(item.unit_price))}</td>
          <td class="number">¥${escapeHtml(formatAmount(item.line_amount))}</td>
          <td>${escapeHtml(formatDate(item.promised_date))}</td>
        </tr>`
    )
    .join("");
  const traceRowsHtml = traces.length
    ? traces
        .map(
          (item, index) => `
            <tr>
              <td>${index + 1}</td>
              <td>${escapeHtml(item.order_no || "-")}</td>
              <td>${escapeHtml(item.delivery_no || "-")}</td>
              <td>${escapeHtml(formatDateTime(item.delivery_date))}</td>
              <td>${escapeHtml(item.product_name || "-")}</td>
              <td>${escapeHtml(item.source_material || "-")}</td>
              <td>${escapeHtml(item.source_inventory_lot_no || "-")}</td>
              <td>${escapeHtml(item.lot_no || "-")}</td>
              <td class="number">${escapeHtml(formatQty(item.delivery_qty))}</td>
              <td class="number">${escapeHtml(formatWeight(item.delivery_weight_kg))}</td>
            </tr>`
        )
        .join("")
    : `<tr><td colspan="10" class="empty">当前所选销售订单暂无发货追溯记录。</td></tr>`;

  return `<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <title>${escapeHtml(contractNo)} 销售合同</title>
  <style>
    * { box-sizing: border-box; }
    body { margin: 0; background: #eef3f8; color: #1f2937; font-family: "Songti SC", "SimSun", "Microsoft YaHei", serif; }
    .toolbar { position: sticky; top: 0; z-index: 5; display: flex; justify-content: flex-end; gap: 10px; padding: 12px 24px; background: rgba(255,255,255,.92); border-bottom: 1px solid #d9e2ec; }
    .toolbar button { border: 1px solid #2563eb; border-radius: 8px; background: #2563eb; color: #fff; padding: 8px 16px; cursor: pointer; font-weight: 700; }
    .contract-page { width: 210mm; min-height: 297mm; margin: 18px auto; padding: 20mm 18mm; background: #fff; box-shadow: 0 18px 50px rgba(15, 23, 42, .16); }
    h1 { margin: 0 0 10px; text-align: center; letter-spacing: 10px; font-size: 28px; }
    .contract-no { text-align: right; color: #475569; margin-bottom: 22px; }
    .meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 24px; margin-bottom: 18px; line-height: 1.8; }
    .section-title { margin: 22px 0 10px; padding-left: 10px; border-left: 4px solid #2563eb; font-weight: 800; font-size: 16px; }
    table { width: 100%; border-collapse: collapse; margin: 8px 0 14px; font-size: 12px; }
    th, td { border: 1px solid #94a3b8; padding: 7px 6px; vertical-align: middle; }
    th { background: #eaf2ff; text-align: center; }
    .number { text-align: right; white-space: nowrap; }
    .empty { text-align: center; color: #64748b; }
    .summary { display: flex; justify-content: flex-end; gap: 28px; margin: 12px 0 20px; font-weight: 800; }
    .terms { margin: 0; padding-left: 22px; line-height: 1.9; }
    .signature { display: grid; grid-template-columns: 1fr 1fr; gap: 46px; margin-top: 38px; }
    .signature-box { min-height: 118px; border-top: 1px solid #334155; padding-top: 12px; line-height: 2; }
    .muted { color: #64748b; }
    @media print {
      body { background: #fff; }
      .toolbar { display: none; }
      .contract-page { width: auto; min-height: auto; margin: 0; padding: 0; box-shadow: none; }
      @page { size: A4; margin: 18mm 14mm; }
    }
  </style>
</head>
<body>
  <div class="toolbar">
    <button onclick="window.print()">打印 / 另存为 PDF</button>
  </div>
  <main class="contract-page">
    <h1>销售合同</h1>
    <div class="contract-no">合同编号：${escapeHtml(contractNo)}</div>

    <div class="meta-grid">
      <div><strong>甲方（买方）：</strong>${escapeHtml(normalizeContractText(customer?.customer_name))}</div>
      <div><strong>乙方（卖方）：</strong>${escapeHtml("嘉恒智能五金")}</div>
      <div><strong>甲方联系人：</strong>${escapeHtml(normalizeContractText(customer?.contact_name))}</div>
      <div><strong>甲方电话：</strong>${escapeHtml(normalizeContractText(customer?.contact_phone))}</div>
      <div><strong>合同日期：</strong>${escapeHtml(currentDateText())}</div>
      <div><strong>来源销售订单：</strong>${escapeHtml(orderNos)}</div>
      <div><strong>交货地址：</strong>${escapeHtml(normalizeContractText(deliveryAddress))}</div>
      <div><strong>约定交期：</strong>${escapeHtml(normalizeContractText(promisedDates || "按销售订单明细交期执行"))}</div>
    </div>

    <div class="section-title">一、产品与价格</div>
    <table>
      <thead>
        <tr>
          <th>序号</th>
          <th>销售订单号</th>
          <th>产品编码</th>
          <th>产品名称</th>
          <th>客户料号</th>
          <th>数量</th>
          <th>单价</th>
          <th>金额</th>
          <th>交期</th>
        </tr>
      </thead>
      <tbody>${lineRowsHtml}</tbody>
    </table>
    <div class="summary">
      <span>合计数量：${escapeHtml(formatQty(totalQty))}</span>
      <span>合同金额：¥${escapeHtml(formatAmount(totalAmount))}</span>
    </div>

    <div class="section-title">二、履约与批次追溯</div>
    <table>
      <thead>
        <tr>
          <th>序号</th>
          <th>销售订单号</th>
          <th>发货单号</th>
          <th>发货时间</th>
          <th>产品</th>
          <th>原材料</th>
          <th>来源库存批次号</th>
          <th>生产批次</th>
          <th>发货数量</th>
          <th>发货重量</th>
        </tr>
      </thead>
      <tbody>${traceRowsHtml}</tbody>
    </table>

    <div class="section-title">三、基础条款</div>
    <ol class="terms">
      <li>产品质量、规格、包装与验收标准以双方确认的图纸、样品、技术文件或销售订单约定为准。</li>
      <li>交货地点按本合同载明地址执行；若甲方临时变更收货信息，应在发货前书面通知乙方。</li>
      <li>本基础模板金额按系统销售订单记录生成；系统未维护税率时，默认按税前金额处理。</li>
      <li>甲方收到货物后应及时验收，如发现数量、质量或包装异常，应在收货后合理期限内通知乙方。</li>
      <li>付款方式、账期、违约责任等商务条款，待双方确认正式合同模板后补充完善。</li>
      <li>本合同为系统基础模板生成文件，正式签署前应由双方业务负责人复核订单、金额、交期和条款。</li>
    </ol>

    <div class="signature">
      <div class="signature-box">
        <strong>甲方（盖章）：</strong><br />
        授权代表：<br />
        日期：
      </div>
      <div class="signature-box">
        <strong>乙方（盖章）：</strong><br />
        授权代表：<br />
        日期：
      </div>
    </div>
    <p class="muted">注：该合同由嘉恒智能五金 ERP 按当前销售订单数据自动生成。</p>
  </main>
</body>
</html>`;
}

function generateSalesContract() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  const orders = selectedContractOrders();
  if (!orders.length) {
    errorMessage.value = "请先勾选需要生成合同的销售订单";
    return;
  }
  const customerIds = Array.from(new Set(orders.map((order) => Number(order.customer_id))));
  if (customerIds.length > 1) {
    errorMessage.value = "销售合同只能按同一客户生成，请不要混选不同客户的销售订单";
    return;
  }
  const lines = buildContractLineRows(orders);
  if (!lines.length) {
    errorMessage.value = "所选销售订单没有订单明细，无法生成合同";
    return;
  }
  const contractWindow = window.open("", "_blank");
  if (!contractWindow) {
    errorMessage.value = "浏览器阻止了合同窗口，请允许弹窗后重试";
    return;
  }
  contractWindow.document.open();
  contractWindow.document.write(renderContractHtml(orders));
  contractWindow.document.close();
  feedbackMessage.value = `已生成 ${orders.length} 张销售订单的基础销售合同`;
}

async function previewDocumentArchive(typeKey, businessId) {
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    await openResource(`/document-archives/${typeKey}/${businessId}/latest/preview`);
  } catch (error) {
    errorMessage.value = error.message || "PDF归档预览失败";
  }
}

async function downloadDocumentArchive(typeKey, businessId, fallbackFilename) {
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    await downloadResource(`/document-archives/${typeKey}/${businessId}/latest/download`, fallbackFilename);
    feedbackMessage.value = "PDF归档已下载";
  } catch (error) {
    errorMessage.value = error.message || "PDF归档下载失败";
  }
}

async function regenerateDocumentArchive(typeKey, businessId) {
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const result = await postResource(`/document-archives/${typeKey}/${businessId}/generate`, {});
    feedbackMessage.value = result.message || "PDF归档已重新生成";
    await loadAll();
  } catch (error) {
    errorMessage.value = error.message || "PDF归档重新生成失败";
  }
}

async function batchDownloadSalesArchives() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  const businessIds = selectedOrderIds.value.map((id) => Number(id)).filter(Boolean);
  if (!businessIds.length) {
    errorMessage.value = "请先勾选需要下载PDF归档的销售订单";
    return;
  }

  try {
    await postDownloadResource("/document-archives/batch-download", { document_type: "sales-order", business_ids: businessIds }, "销售订单归档.zip");
    feedbackMessage.value = `已下载 ${businessIds.length} 张销售订单PDF归档`;
  } catch (error) {
    errorMessage.value = error.message || "销售订单PDF归档批量下载失败";
  }
}

function resetCustomerForm() {
  editingCustomerId.value = null;
  Object.assign(customerForm, buildEmptyCustomerForm());
}

function resetSalesOrderForm(customerId = "") {
  const customer = customers.value.find((item) => Number(item.id) === Number(customerId));
  Object.assign(salesOrderForm, buildEmptySalesOrderForm(), {
    customer_id: customerId,
    sales_employee_id: defaultEmployeeIdFromSession(salesEmployeeOptions.value),
    delivery_address: customer?.address || ""
  });
}

function openCustomerDrawer() {
  resetCustomerForm();
  feedbackMessage.value = "";
  errorMessage.value = "";
  customerDrawerOpen.value = true;
}

function openCustomerEditDrawer(customer) {
  resetCustomerForm();
  editingCustomerId.value = customer.id;
  Object.assign(customerForm, {
    customer_name: customer.customer_name || "",
    short_name: customer.short_name || "",
    contacts: contactsForForm(customer),
    address: customer.address || "",
    credit_days: Number(customer.credit_days || 30)
  });
  feedbackMessage.value = "";
  errorMessage.value = "";
  customerDrawerOpen.value = true;
}

function closeCustomerDrawer() {
  customerDrawerOpen.value = false;
  resetCustomerForm();
}

function openSalesOrderDrawer() {
  resetSalesOrderForm();
  feedbackMessage.value = "";
  errorMessage.value = "";
  salesOrderDrawerOpen.value = true;
}

function openSalesOrderDetailDrawer(order) {
  selectedOrderId.value = Number(order.order_id);
  orderDetailDrawerOpen.value = true;
}

function canDeleteSalesOrder(order) {
  return Boolean(order?.can_delete);
}

function deleteSalesOrderTitle(order) {
  if (canDeleteSalesOrder(order)) {
    return "未关联采购和发货，可以删除";
  }
  if (Number(order?.purchase_order_count || 0) > 0) {
    return "已关联采购订单，不能删除";
  }
  if (Number(order?.delivery_count || 0) > 0 || Number(order?.delivery_item_count || 0) > 0) {
    return "已有发货记录，不能删除";
  }
  if (Number(order?.work_order_count || 0) > 0) {
    return "已关联生产工单，不能删除";
  }
  return "当前销售订单不能删除";
}

function applySalesCustomerDefaults() {
  const customer = customers.value.find((item) => Number(item.id) === Number(salesOrderForm.customer_id));
  salesOrderForm.delivery_address = customer?.address || "";
}

function addSalesOrderItem() {
  salesOrderForm.items.push(buildSalesOrderItemRow(salesOrderForm.promised_date));
}

function removeSalesOrderItem(index) {
  salesOrderForm.items.splice(index, 1);
}

function syncSalesOrderItemPromisedDatesFromHeader() {
  salesOrderForm.items.forEach((item) => {
    if (!item.promised_date_touched || !item.promised_date) {
      item.promised_date = salesOrderForm.promised_date || "";
    }
  });
}

function markSalesOrderItemPromisedDateTouched(item) {
  item.promised_date_touched = true;
}

async function loadCustomers() {
  customers.value = await fetchResource("/sales/customers?limit=200", []);
}

function triggerCustomerImport() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  if (customerImportInputRef.value) {
    customerImportInputRef.value.value = "";
    customerImportInputRef.value.click();
  }
}

async function importCustomers(event) {
  const file = event.target.files?.[0];
  if (!file) {
    return;
  }

  customerImporting.value = true;
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const formData = new FormData();
    formData.append("file", file);
    const result = await uploadResource("/sales/customers/import", formData);
    feedbackMessage.value = result.message || "客户名录导入完成";
    if (result.errors?.length) {
      errorMessage.value = result.errors.join("；");
    }
    await loadCustomers();
  } catch (error) {
    errorMessage.value = error.message || "客户名录导入失败";
  } finally {
    customerImporting.value = false;
    if (customerImportInputRef.value) {
      customerImportInputRef.value.value = "";
    }
  }
}

async function exportCustomers() {
  customerExporting.value = true;
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    await downloadResource("/sales/customers/export", "客户名录.xlsx");
    feedbackMessage.value = "客户名录已导出";
  } catch (error) {
    errorMessage.value = error.message || "客户名录导出失败";
  } finally {
    customerExporting.value = false;
  }
}

async function loadAll() {
  const [customerRows, productRows, salesEmployeeRows, orderRowsResult, orderItemRows, deliveryRows, deliveryItemRows] = await Promise.all([
    fetchResource("/sales/customers?limit=200", []),
    fetchResource("/master-data/products?limit=200", []),
    fetchPermissionEmployeeOptions(PERSONNEL_PERMISSION_CODES.SALES_ORDER),
    fetchResource("/sales/orders?limit=500", []),
    fetchResource("/sales/order-items?limit=500", []),
    fetchResource("/sales/deliveries?limit=500", []),
    fetchResource("/sales/delivery-items?limit=500", [])
  ]);
  customers.value = customerRows;
  products.value = productRows;
  salesEmployeeOptions.value = salesEmployeeRows;
  salesOrders.value = orderRowsResult;
  salesOrderItems.value = orderItemRows;
  deliveries.value = deliveryRows;
  deliveryItems.value = deliveryItemRows;
  if (!salesOrderForm.sales_employee_id) {
    salesOrderForm.sales_employee_id = defaultEmployeeIdFromSession(salesEmployeeRows);
  }
  selectedOrderIds.value = selectedOrderIds.value.filter((id) => orderRowsResult.some((order) => Number(order.order_id) === Number(id)));
}

async function submitCustomer() {
  customerSubmitting.value = true;
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const contacts = normalizedCustomerContacts();
    const payload = {
      ...customerForm,
      contact_name: contacts.map((contact) => contact.contact_name).filter(Boolean).join("、") || null,
      contact_phone: contacts.map((contact) => contact.contact_phone).filter(Boolean).join("、") || null,
      contacts,
      credit_days: Number(customerForm.credit_days || 0)
    };
    const result = editingCustomerId.value
      ? await putResource(`/sales/customers/${editingCustomerId.value}`, payload)
      : await postResource("/sales/customers", payload);
    feedbackMessage.value = `客户 ${result.customer_name} 已保存`;
    await loadCustomers();
    salesOrderForm.customer_id = result.id;
    salesOrderForm.delivery_address = result.address || "";
    customerDrawerOpen.value = false;
    resetCustomerForm();
  } catch (error) {
    errorMessage.value = error.message || "创建客户失败";
  } finally {
    customerSubmitting.value = false;
  }
}

async function submitSalesOrder() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  const items = salesOrderForm.items
    .map((item) => ({
      product_item_id: Number(item.product_item_id),
      order_qty: Number(item.order_qty || 0),
      unit_price: Number(item.unit_price || 0),
      promised_date: item.promised_date || salesOrderForm.promised_date || null,
      customer_part_no: item.customer_part_no || null
    }))
    .filter((item) => item.product_item_id && item.order_qty > 0);
  if (!items.length) {
    errorMessage.value = "销售订单至少需要一条有效明细";
    return;
  }

  salesOrderSubmitting.value = true;
  try {
    const createdCustomerId = Number(salesOrderForm.customer_id);
    const result = await postResource("/sales/orders", {
      customer_id: createdCustomerId,
      sales_employee_id: salesOrderForm.sales_employee_id ? Number(salesOrderForm.sales_employee_id) : null,
      promised_date: salesOrderForm.promised_date || null,
      delivery_address: salesOrderForm.delivery_address || null,
      tax_rate: Number(salesOrderForm.tax_rate || 0),
      remark: salesOrderForm.remark || null,
      items
    });
    feedbackMessage.value = `销售订单 ${result.order_no} 已创建`;
    selectedOrderId.value = result.order_id;
    salesOrderDrawerOpen.value = false;
    orderDetailDrawerOpen.value = true;
    await loadAll();
    resetSalesOrderForm(createdCustomerId);
  } catch (error) {
    errorMessage.value = error.message || "创建销售订单失败";
  } finally {
    salesOrderSubmitting.value = false;
  }
}

async function deleteSalesOrderRow(order) {
  if (!canDeleteSalesOrder(order)) {
    return;
  }
  const confirmed = window.confirm(`确认删除销售订单 ${order.order_no}？`);
  if (!confirmed) {
    return;
  }
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const result = await deleteResource(`/sales/orders/${Number(order.order_id)}`);
    feedbackMessage.value = result.message || `销售订单 ${order.order_no} 已删除`;
    selectedOrderIds.value = selectedOrderIds.value.filter((id) => Number(id) !== Number(order.order_id));
    if (Number(selectedOrderId.value) === Number(order.order_id)) {
      selectedOrderId.value = null;
      orderDetailDrawerOpen.value = false;
    }
    await loadAll();
  } catch (error) {
    errorMessage.value = error.message || "销售订单删除失败";
  }
}

function splitContactText(value) {
  return String(value || "")
    .split(/[、,，;；\n]+/)
    .map((item) => item.trim())
    .filter(Boolean);
}

function displayContacts(row) {
  const contacts = Array.isArray(row?.contacts)
    ? row.contacts
        .map((contact) => ({
          contact_name: String(contact?.contact_name || "").trim(),
          contact_phone: String(contact?.contact_phone || "").trim()
        }))
        .filter((contact) => contact.contact_name || contact.contact_phone)
    : [];
  if (contacts.length) {
    return contacts.slice(0, 3);
  }
  const names = splitContactText(row?.contact_name);
  const phones = splitContactText(row?.contact_phone);
  const total = Math.min(Math.max(names.length, phones.length), 3);
  return Array.from({ length: total }, (_, index) => ({
    contact_name: names[index] || "",
    contact_phone: phones[index] || ""
  }));
}

function contactsForForm(row) {
  const contacts = displayContacts(row);
  return contacts.length ? contacts.map((contact) => ({ ...contact })) : [buildEmptyContact()];
}

function normalizedCustomerContacts() {
  return customerForm.contacts
    .map((contact) => ({
      contact_name: String(contact.contact_name || "").trim(),
      contact_phone: String(contact.contact_phone || "").trim()
    }))
    .filter((contact) => contact.contact_name || contact.contact_phone)
    .slice(0, 3);
}

function addCustomerContact() {
  if (customerForm.contacts.length < 3) {
    customerForm.contacts.push(buildEmptyContact());
  }
}

function removeCustomerContact(index) {
  if (customerForm.contacts.length <= 1) {
    Object.assign(customerForm.contacts[0], buildEmptyContact());
    return;
  }
  customerForm.contacts.splice(index, 1);
}

function formatContactNames(row) {
  const names = displayContacts(row).map((contact) => contact.contact_name).filter(Boolean);
  return names.length ? names.join("、") : "-";
}

function formatContactPhones(row) {
  const phones = displayContacts(row).map((contact) => contact.contact_phone).filter(Boolean);
  return phones.length ? phones.join("、") : "-";
}

onMounted(async () => {
  await loadAll();
});
</script>

<style scoped>
.sales-order-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 48px;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(232, 237, 246, 0.9);
}

.order-panel-left-actions {
  display: flex;
  align-items: center;
  justify-content: flex-start;
}

.contract-header-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 86px;
  min-height: 38px;
  padding: 0 16px;
  border: 1px solid #409eff;
  border-radius: 10px;
  background: linear-gradient(180deg, #66b1ff 0%, #409eff 100%);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 8px 20px rgba(64, 158, 255, 0.22);
  cursor: pointer;
  transition: transform 0.16s ease, box-shadow 0.16s ease, opacity 0.16s ease;
}

.contract-header-button:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 12px 26px rgba(64, 158, 255, 0.28);
}

.contract-header-button:disabled {
  cursor: not-allowed;
  opacity: 0.52;
}

.select-col {
  width: 44px;
  text-align: center;
}

.select-col input {
  width: 16px;
  height: 16px;
  accent-color: #409eff;
  cursor: pointer;
}

.trace-cell {
  max-width: 360px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sales-archive-col,
.sales-archive-cell {
  width: 188px;
  min-width: 188px;
}

.sales-archive-cell {
  overflow: visible;
  white-space: normal;
}

.sales-archive-actions-compact {
  width: 172px;
}

.sales-archive-actions-compact :deep(.document-archive-actions) {
  display: grid;
  gap: 6px;
}

.sales-archive-actions-compact :deep(.document-archive-status) {
  min-height: 24px;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 11px;
  line-height: 1.2;
  white-space: nowrap;
}

.sales-archive-actions-compact :deep(.document-archive-buttons) {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
}

.sales-archive-actions-compact :deep(.document-archive-button) {
  min-height: 26px;
  padding: 0 5px;
  border-radius: 8px;
  font-size: 11px;
  line-height: 1;
  white-space: nowrap;
}

.sales-archive-actions-compact :deep(.document-archive-icon) {
  display: none;
}

.table-action-button {
  min-height: 30px;
  padding: 0 10px;
  white-space: nowrap;
}

.drawer-form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

.drawer-form-actions .primary-button {
  min-width: 132px;
}

@media (max-width: 560px) {
  .drawer-form-actions .primary-button {
    width: 100%;
  }
}
</style>
