<template>
  <n-modal
    v-model:show="visible"
    preset="card"
    title="拆分工单"
    :style="{ width: '1120px' }"
    :content-style="{ paddingTop: '8px', paddingBottom: '4px' }"
    :mask-closable="false"
    @after-leave="resetState"
  >
    <n-spin :show="loading">
      <div class="split-scroll">
        <n-descriptions v-if="preview" :column="3" label-placement="left" size="small" class="split-desc">
          <n-descriptions-item label="原工单编号">{{ preview.workOrderCode || '-' }}</n-descriptions-item>
          <n-descriptions-item label="物料编码">{{ preview.materialCode || '-' }}</n-descriptions-item>
          <n-descriptions-item label="物料/订单">{{ preview.orderItemName || '-' }}</n-descriptions-item>
          <n-descriptions-item label="计划数量">{{ preview.quantity ?? 0 }}</n-descriptions-item>
          <n-descriptions-item label="已进入生产">{{ preview.investedQty ?? 0 }}</n-descriptions-item>
          <n-descriptions-item label="可拆数量">{{ preview.splittableQty ?? 0 }}</n-descriptions-item>
          <n-descriptions-item label="原工序" :span="3">
            {{ preview.processCount ?? 0 }} 道
            <span v-if="preview.processNames?.length" class="process-names">
              （{{ preview.processNames.join('、') }}）
            </span>
          </n-descriptions-item>
        </n-descriptions>

        <n-alert v-if="preview && !preview.canSplit" type="warning" :bordered="false" style="margin: 8px 0">
          {{ preview.reason || '当前工单不允许拆单' }}
        </n-alert>

        <template v-if="preview?.canSplit">
          <div class="split-section">
            <div class="split-section-title">数量分配</div>
            <div class="field-row">
              <span class="field-label-inline">拆分方式</span>
              <n-radio-group v-model:value="mode" name="splitMode" size="small">
                <n-space>
                  <n-radio value="equal">等量拆分</n-radio>
                  <n-radio value="custom">指定数量</n-radio>
                </n-space>
              </n-radio-group>
            </div>

            <!-- 等量：按总份数均分计划数量，第1份留原单，其余新建 -->
            <div v-if="mode === 'equal'" class="split-body">
              <div class="field-row">
                <span class="field-label-inline">拆成份数</span>
                <n-input-number
                  v-model:value="equalCount"
                  :min="2"
                  :max="Math.max(2, maxEqualParts)"
                  :precision="0"
                  size="small"
                  style="width: 140px"
                />
                <span class="hint-inline">含原工单，第1份留原单</span>
              </div>
              <div class="hint-inline" style="margin-top: 6px">{{ equalHint }}</div>
            </div>

            <!-- 指定：手动设原单保留 + 各新工单数量 -->
            <div v-else class="split-body">
              <div class="field-row">
                <span class="field-label-inline">原单保留</span>
                <n-input-number
                  v-model:value="keepQty"
                  :min="unsplittableQty"
                  :max="Math.max(unsplittableQty, (preview.quantity ?? 0) - 1)"
                  :precision="0"
                  size="small"
                  style="width: 140px"
                  @update:value="onKeepQtyUpdate"
                />
                <span class="hint-inline">≥不可拆 {{ unsplittableQty }}，拆出 {{ splitOutQty }}</span>
              </div>
              <div v-for="(row, idx) in customRows" :key="idx" class="custom-row">
                <n-input-number
                  v-model:value="customRows[idx]"
                  :min="1"
                  :precision="0"
                  size="small"
                  placeholder="新工单数量"
                  style="flex: 1"
                />
                <n-button text type="error" :disabled="customRows.length <= 1" @click="removeCustomRow(idx)">
                  删除
                </n-button>
              </div>
              <n-button dashed block size="small" style="margin-top: 6px" @click="addCustomRow">+ 添加工单</n-button>
              <div class="sum-line" :class="{ error: customSum !== splitOutQty }">
                拆出合计: {{ customSum }} / {{ splitOutQty }}
              </div>
            </div>
          </div>

          <div class="split-section">
            <div class="split-section-title">
              新工单工艺路线
              <n-radio-group
                v-model:value="routeMode"
                name="routeMode"
                size="small"
                style="margin-left: 12px; font-weight: 400"
              >
                <n-space>
                  <n-radio value="kingdee">金蝶工艺路线</n-radio>
                  <n-radio value="assemble">创建新工艺路线</n-radio>
                </n-space>
              </n-radio-group>
            </div>

            <div v-if="routeMode === 'kingdee'" class="split-body">
              <div v-if="!preview?.materialCode" class="hint">当前订单无物料编码，无法查询金蝶工艺路线</div>
              <template v-else>
                <div class="kingdee-layout">
                  <div class="kingdee-left">
                    <div class="field-label">路线列表（{{ routeList.length }}）</div>
                    <n-spin :show="routeLoading">
                      <div v-if="!routeLoading && routeList.length === 0" class="hint">未查询到工艺路线</div>
                      <div v-else class="route-card-list">
                        <div
                          v-for="route in routeList"
                          :key="route.routingNo"
                          class="route-card"
                          :class="{ active: routingNo === route.routingNo }"
                          @click="routingNo = route.routingNo || null"
                        >
                          <div class="route-card-head">
                            <span class="route-code">{{ route.routingNo }}</span>
                            <span class="route-step-count">{{ route.stepCount ?? route.steps?.length ?? 0 }}道</span>
                          </div>
                          <div class="route-flow">
                            {{ (route.processNames || []).join(' → ') || '暂无工序' }}
                          </div>
                        </div>
                      </div>
                    </n-spin>
                  </div>
                  <div class="kingdee-right">
                    <div class="field-label">
                      工序明细
                      <span v-if="selectedRoute" class="route-detail-sub">
                        {{ selectedRoute.routingNo }} · {{ selectedSteps.length }} 道
                      </span>
                    </div>
                    <n-data-table
                      v-if="selectedRoute"
                      size="small"
                      :bordered="true"
                      :single-line="true"
                      :columns="kingdeeStepColumns"
                      :data="selectedSteps"
                      :scroll-x="900"
                      :max-height="260"
                      :pagination="false"
                    />
                    <div v-else class="route-detail-empty">点击左侧路线查看工序</div>
                  </div>
                </div>
              </template>
            </div>

            <div v-else class="split-body">
              <div class="assemble-toolbar">
                <span class="hint-inline">新增工艺路线方；说明为空时默认用工序名称</span>
                <n-button size="small" type="primary" secondary @click="addAssembleRow">+ 添加工序</n-button>
              </div>
              <n-data-table
                size="small"
                :bordered="true"
                :single-line="false"
                :columns="assembleColumns"
                :data="assembleRows"
                :scroll-x="1080"
                :max-height="280"
                :pagination="false"
              />
            </div>
          </div>
        </template>
      </div>
    </n-spin>

    <template #footer>
      <n-space justify="end">
        <n-button @click="visible = false">取消</n-button>
        <n-button type="primary" :loading="submitting" :disabled="!canConfirm" @click="confirmSplit">
          确认拆分
        </n-button>
      </n-space>
    </template>
  </n-modal>
</template>

<script setup lang="ts">
/**
 * 拆单弹窗：
 * - 已进入生产数量（不可拆）留原单；只拆可拆数量
 * - 等量拆分：按「拆成份数」均分计划数量，第1份留原单，其余新建（如 30÷3 → 原10 + 新10 + 新10）
 * - 指定数量：手动设原单保留 + 各新工单数量
 * - 金蝶工艺路线 / 工序表组装（对齐工艺路线字段）
 */
import { computed, h, ref, watch } from 'vue'
import {
  NAlert,
  NButton,
  NDataTable,
  NDescriptions,
  NDescriptionsItem,
  NInput,
  NInputNumber,
  NModal,
  NRadio,
  NRadioGroup,
  NSelect,
  NSpace,
  NSpin,
  NSwitch,
  useMessage,
  type DataTableColumns,
  type SelectOption,
} from 'naive-ui'
import {
  orderProcessPlanApi,
  type ProcessPlanSplitPreview,
  type ProcessPlanSplitStep,
} from '@/api/orderProcessPlan'
import {
  processRouteApi,
  type KingdeeProcessRouteStep,
  type ProcessRouteSelectOption,
} from '@/api/processRoute'
import { basicProcessPlanApi, type BasicProcessPlan } from '@/api/basicProcessPlan'

interface AssembleRow extends ProcessPlanSplitStep {
  _key: string
}

const props = defineProps<{
  show: boolean
  planId: number | null
}>()

const emit = defineEmits<{
  'update:show': [value: boolean]
  success: []
}>()

const message = useMessage()
const loading = ref(false)
const submitting = ref(false)
const preview = ref<ProcessPlanSplitPreview | null>(null)

const mode = ref<'equal' | 'custom'>('equal')
const keepQty = ref(0)
/** 等量拆分：总份数（含原单），至少 2 = 原单 + 1 新单 */
const equalCount = ref(2)
const customRows = ref<(number | null)[]>([null])

const routeMode = ref<'kingdee' | 'assemble'>('kingdee')
const routingNo = ref<string | null>(null)
const routeList = ref<ProcessRouteSelectOption[]>([])
const routeLoading = ref(false)
const processLoading = ref(false)

const processOptions = ref<SelectOption[]>([])
const processMap = ref<Record<number, BasicProcessPlan>>({})
const assembleRows = ref<AssembleRow[]>([])
const ctrlCodeOptions: SelectOption[] = [
  { label: '汇报+免检', value: '汇报+免检' },
  { label: '汇报+质量', value: '汇报+质量' },
  { label: '委外+质量', value: '委外+质量' },
  { label: '委外+汇报', value: '委外+汇报' },
]
const activityUnitOptions = ref<SelectOption[]>([
  { label: '小时', value: '小时' },
  { label: '分钟', value: '分钟' },
  { label: '秒', value: '秒' },
])

const visible = computed({
  get: () => props.show,
  set: (v: boolean) => emit('update:show', v),
})

const unsplittableQty = computed(() => preview.value?.investedQty ?? 0)
const planQty = computed(() => preview.value?.quantity ?? 0)
const splitOutQty = computed(() => Math.max(planQty.value - (keepQty.value ?? 0), 0))

function onKeepQtyUpdate(v: number | null) {
  const min = unsplittableQty.value
  const max = Math.max(min, (preview.value?.quantity ?? 0) - 1)
  if (v == null || v < min) {
    keepQty.value = min
    return
  }
  if (v > max) keepQty.value = max
}

/**
 * 等量拆分：把整单计划数量均分成 N 份（含原单）。
 * quantities = [原单保留, 新单1, 新单2, ...]
 */
const equalQuantities = computed(() => {
  const q = planQty.value
  const n = equalCount.value
  if (!q || !n || n < 2 || q < n) return [] as number[]
  const base = Math.floor(q / n)
  const rem = q % n
  const list = Array.from({ length: n }, () => base)
  // 余数加在最后一份，避免中间份变成 0
  list[n - 1] = base + rem
  if (list.some((v) => v <= 0)) return []
  // 第1份必须盖住不可拆（已进入生产）数量
  if (list[0] < unsplittableQty.value) return []
  return list
})

/** 在「第1份 ≥ 不可拆」前提下，最多能拆成几份 */
const maxEqualParts = computed(() => {
  const q = planQty.value
  const inv = unsplittableQty.value
  if (q < 2) return 2
  let max = Math.min(q, Math.max(2, q - inv)) // 至少留 1 给某新单时可拆上限粗估
  // 收紧：floor(q/n) >= inv（余数在末份时首份=floor）
  while (max > 2 && Math.floor(q / max) < inv) {
    max -= 1
  }
  // 还要保证至少能拆出 1 个新单：首份 < q
  while (max > 2) {
    const base = Math.floor(q / max)
    if (base >= Math.max(1, inv) && base < q) break
    max -= 1
  }
  return Math.max(2, max)
})

const equalHint = computed(() => {
  const list = equalQuantities.value
  if (!list.length) {
    if (planQty.value < equalCount.value) return `计划数量不足以分成 ${equalCount.value} 份`
    if (equalCount.value >= 2 && Math.floor(planQty.value / equalCount.value) < unsplittableQty.value) {
      return `第1份无法覆盖不可拆数量 ${unsplittableQty.value}，请减少份数`
    }
    return ''
  }
  const keep = list[0]
  const news = list.slice(1)
  const newCount = news.length
  if (news.every((v) => v === news[0])) {
    return `结果：原单保留 ${keep}，新建 ${newCount} 张各 ${news[0]}（共 ${list.length} 张）`
  }
  return `结果：原单保留 ${keep}，新建 ${newCount} 张（${news.join('、')}）`
})

const customSum = computed(() =>
  customRows.value.reduce((s, v) => s + (typeof v === 'number' && v > 0 ? v : 0), 0),
)

const selectedRoute = computed(() =>
  routingNo.value ? routeList.value.find((r) => r.routingNo === routingNo.value) ?? null : null,
)
const selectedSteps = computed<KingdeeProcessRouteStep[]>(() => selectedRoute.value?.steps ?? [])

const kingdeeStepColumns: DataTableColumns<KingdeeProcessRouteStep> = [
  { title: '工序号', key: 'operNumber', width: 70, render: (r) => r.operNumber ?? '-' },
  { title: '工序编码', key: 'processCode', width: 110, ellipsis: { tooltip: true }, render: (r) => r.processCode || '-' },
  { title: '工序名称', key: 'processName', width: 120, ellipsis: { tooltip: true }, render: (r) => r.processName || '-' },
  { title: '工序说明', key: 'operDescription', minWidth: 140, ellipsis: { tooltip: true }, render: (r) => r.operDescription || '-' },
  { title: '工作中心', key: 'workCenterName', width: 110, ellipsis: { tooltip: true }, render: (r) => r.workCenterName || '-' },
  { title: '车间', key: 'departmentName', width: 100, ellipsis: { tooltip: true }, render: (r) => r.departmentName || '-' },
  { title: '控制码', key: 'optCtrlCodeName', width: 100, ellipsis: { tooltip: true }, render: (r) => r.optCtrlCodeName || '-' },
  {
    title: '标准工时',
    key: 'activityQty',
    width: 100,
    render: (r) => (r.activityQty == null ? '-' : `${r.activityQty}${r.activityUnit ? ' ' + r.activityUnit : ''}`),
  },
  { title: '质检', key: 'qualityInspection', width: 56, render: (r) => (r.qualityInspection === 1 ? '是' : '否') },
  { title: '入库', key: 'storageEntry', width: 56, render: (r) => (r.storageEntry === 1 ? '是' : '否') },
]

function createEmptyAssembleRow(operNumber = 10): AssembleRow {
  return {
    _key: `a-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
    processId: null,
    operNumber,
    processCode: null,
    processName: null,
    operDescription: null,
    sectionId: null,
    workshopId: null,
    activityUnit: '小时',
    optCtrlCodeName: null,
    activityQty: null,
    qualityInspection: 0,
    storageEntry: 0,
    procurement: 0,
    isOutsource: 0,
  }
}

function renumberAssembleRows() {
  assembleRows.value.forEach((row, i) => {
    row.operNumber = (i + 1) * 10
  })
}

function addAssembleRow() {
  assembleRows.value.push(createEmptyAssembleRow((assembleRows.value.length + 1) * 10))
}

function removeAssembleRow(key: string) {
  if (assembleRows.value.length <= 1) return
  assembleRows.value = assembleRows.value.filter((r) => r._key !== key)
  renumberAssembleRows()
}

function onAssembleProcessChange(row: AssembleRow, processId: number | null) {
  row.processId = processId
  if (processId == null) {
    row.processCode = null
    row.processName = null
    row.operDescription = null
    row.sectionId = null
    row.workshopId = null
    row.qualityInspection = 0
    row.storageEntry = 0
    row.procurement = 0
    row.isOutsource = 0
    return
  }
  const basic = processMap.value[processId]
  if (!basic) return
  row.processCode = basic.code || null
  row.processName = basic.name || null
  if (!row.operDescription) {
    row.operDescription = basic.operDescription || basic.name || null
  }
  row.sectionId = basic.sectionId ?? null
  row.workshopId = basic.workShopId ?? null
  row.qualityInspection = basic.qualityInspection ?? 0
  row.storageEntry = basic.storageEntry ?? 0
  row.procurement = basic.procurement ?? 0
  row.isOutsource = basic.outsource ?? 0
}

function onCtrlCodeChange(row: AssembleRow, val: string | null) {
  row.optCtrlCodeName = val
  if (!val) return
  // 含「质量」→ 质检；含「委外」→ 委外；「免检」→ 不质检
  row.qualityInspection = val.includes('质量') ? 1 : 0
  row.isOutsource = val.includes('委外') ? 1 : 0
}

const assembleColumns = computed<DataTableColumns<AssembleRow>>(() => [
  {
    title: '工序号',
    key: 'operNumber',
    width: 64,
    render: (row) => row.operNumber ?? '-',
  },
  {
    title: '工序',
    key: 'processId',
    width: 180,
    render: (row) =>
      h(NSelect, {
        value: row.processId,
        size: 'small',
        filterable: true,
        clearable: true,
        options: processOptions.value,
        loading: processLoading.value,
        placeholder: '选择工序',
        style: 'width: 100%',
        onUpdateValue: (v: number | null) => onAssembleProcessChange(row, v),
      }),
  },
  {
    title: '工序说明',
    key: 'operDescription',
    width: 150,
    render: (row) =>
      h(NInput, {
        value: row.operDescription ?? '',
        size: 'small',
        clearable: true,
        placeholder: row.processName || '默认工序名称',
        onUpdateValue: (v: string) => {
          row.operDescription = v
        },
      }),
  },
  {
    title: '标准工时',
    key: 'activityQty',
    width: 100,
    render: (row) =>
      h(NInputNumber, {
        value: row.activityQty,
        size: 'small',
        min: 0,
        precision: 3,
        style: 'width: 90px',
        placeholder: '工时',
        onUpdateValue: (v: number | null) => {
          row.activityQty = v
        },
      }),
  },
  {
    title: '单位',
    key: 'activityUnit',
    width: 100,
    render: (row) =>
      h(NSelect, {
        value: row.activityUnit,
        size: 'small',
        filterable: true,
        tag: true,
        options: activityUnitOptions.value,
        placeholder: '单位',
        style: 'width: 100%',
        onUpdateValue: (v: string | null) => {
          row.activityUnit = v
        },
      }),
  },
  {
    title: '控制码',
    key: 'optCtrlCodeName',
    width: 140,
    render: (row) =>
      h(NSelect, {
        value: row.optCtrlCodeName,
        size: 'small',
        filterable: true,
        clearable: true,
        options: ctrlCodeOptions,
        placeholder: '选择控制码',
        style: 'width: 100%',
        onUpdateValue: (v: string | null) => onCtrlCodeChange(row, v),
      }),
  },
  {
    title: '质检',
    key: 'qualityInspection',
    width: 70,
    render: (row) =>
      h(NSwitch, {
        value: row.qualityInspection === 1,
        size: 'small',
        onUpdateValue: (v: boolean) => {
          row.qualityInspection = v ? 1 : 0
        },
      }),
  },
  {
    title: '入库',
    key: 'storageEntry',
    width: 70,
    render: (row) =>
      h(NSwitch, {
        value: row.storageEntry === 1,
        size: 'small',
        onUpdateValue: (v: boolean) => {
          row.storageEntry = v ? 1 : 0
        },
      }),
  },
  {
    title: '操作',
    key: 'actions',
    width: 64,
    fixed: 'right',
    render: (row) =>
      h(
        NButton,
        {
          text: true,
          type: 'error',
          size: 'small',
          disabled: assembleRows.value.length <= 1,
          onClick: () => removeAssembleRow(row._key),
        },
        { default: () => '删除' },
      ),
  },
])

const assembleValid = computed(() => {
  if (!assembleRows.value.length) return false
  return assembleRows.value.every((r) => r.processId != null || !!r.processName || !!r.processCode)
})

const canConfirm = computed(() => {
  if (!preview.value?.canSplit || submitting.value) return false

  if (mode.value === 'equal') {
    // 等量：整单均分，列表本身已含原单保留
    if (!equalQuantities.value.length) return false
  } else {
    if (keepQty.value == null || keepQty.value < unsplittableQty.value) return false
    if (splitOutQty.value <= 0) return false
    if (customRows.value.length < 1) return false
    if (customRows.value.some((v) => v == null || v <= 0)) return false
    if (customSum.value !== splitOutQty.value) return false
  }

  if (routeMode.value === 'kingdee') return !!routingNo.value
  return assembleValid.value
})

watch(
  () => [props.show, props.planId] as const,
  async ([show, planId]) => {
    if (!show || planId == null) return
    await loadPreview(planId)
    await Promise.all([
      loadRouteOptions(preview.value?.materialCode),
      loadProcessOptions(),
    ])
  },
)

watch(keepQty, () => {
  if (mode.value === 'custom') {
    customRows.value = [splitOutQty.value > 0 ? splitOutQty.value : null]
  }
})

async function loadPreview(planId: number) {
  loading.value = true
  preview.value = null
  try {
    preview.value = await orderProcessPlanApi.splitPreview(planId)
    const unsplittable = preview.value?.investedQty ?? 0
    keepQty.value = unsplittable
    // 默认拆成 2 份（原单 + 1 新单）；数量够时也可改成更多
    equalCount.value = 2
    customRows.value = [preview.value?.splittableQty ?? null]
    mode.value = 'equal'
    routeMode.value = 'kingdee'
    routingNo.value = null
    assembleRows.value = [createEmptyAssembleRow(10)]
  } catch (e: any) {
    message.error(e?.message || '加载拆单预览失败')
    visible.value = false
  } finally {
    loading.value = false
  }
}

async function loadRouteOptions(materialCode?: string | null) {
  routeLoading.value = true
  routeList.value = []
  routingNo.value = null
  try {
    if (!materialCode) return
    const list = (await processRouteApi.kingdeeSelect(materialCode)) as ProcessRouteSelectOption[]
    routeList.value = (Array.isArray(list) ? list : []).filter((r) => !!r?.routingNo)
  } catch (e: any) {
    routeList.value = []
    message.error(e?.message || '加载金蝶工艺路线失败')
  } finally {
    routeLoading.value = false
  }
}

async function loadProcessOptions() {
  processLoading.value = true
  try {
    const page: any = await basicProcessPlanApi.page({ page: 1, pageSize: 500 })
    const rows: BasicProcessPlan[] = page?.records ?? page?.list ?? (Array.isArray(page) ? page : [])
    const map: Record<number, BasicProcessPlan> = {}
    processOptions.value = rows
      .filter((r) => r?.id != null)
      .map((r) => {
        const id = Number(r.id)
        map[id] = r
        return {
          label: `${r.code || ''} ${r.name || ''}`.trim() || String(id),
          value: id,
        }
      })
    processMap.value = map
  } catch {
    processOptions.value = []
    processMap.value = {}
  } finally {
    processLoading.value = false
  }
}

function addCustomRow() {
  customRows.value.push(null)
}

function removeCustomRow(idx: number) {
  if (customRows.value.length <= 1) return
  customRows.value.splice(idx, 1)
}

function resetState() {
  preview.value = null
  mode.value = 'equal'
  keepQty.value = 0
  equalCount.value = 2
  customRows.value = [null]
  routeMode.value = 'kingdee'
  routingNo.value = null
  routeList.value = []
  assembleRows.value = [createEmptyAssembleRow(10)]
}

function buildAssembleSteps(): ProcessPlanSplitStep[] {
  return assembleRows.value.map((row, i) => {
    const name = row.processName || processMap.value[row.processId!]?.name || null
    const desc = (row.operDescription || '').trim() || name
    return {
      processId: row.processId,
      operNumber: row.operNumber ?? (i + 1) * 10,
      processCode: row.processCode,
      processName: name,
      operDescription: desc,
      sectionId: row.sectionId,
      workshopId: row.workshopId,
      activityUnit: row.activityUnit,
      optCtrlCodeName: row.optCtrlCodeName,
      activityQty: row.activityQty,
      qualityInspection: row.qualityInspection ?? 0,
      storageEntry: row.storageEntry ?? 0,
      procurement: row.procurement ?? 0,
      isOutsource: row.isOutsource ?? 0,
    }
  })
}

async function confirmSplit() {
  if (!props.planId || !canConfirm.value) return
  // 等量：列表已含原单；指定：拼上 keepQty
  const quantities =
    mode.value === 'equal'
      ? equalQuantities.value
      : [keepQty.value!, ...customRows.value.map((v) => Number(v))]
  submitting.value = true
  try {
    await orderProcessPlanApi.split({
      planId: props.planId,
      quantities,
      routeMode: routeMode.value,
      routingNo: routeMode.value === 'kingdee' ? routingNo.value : null,
      assembleSteps: routeMode.value === 'assemble' ? buildAssembleSteps() : undefined,
    })
    message.success('拆单成功')
    visible.value = false
    emit('success')
  } catch (e: any) {
    message.error(e?.message || '拆单失败')
  } finally {
    submitting.value = false
  }
}
</script>

<style scoped>
.split-scroll {
  max-height: min(72vh, 680px);
  overflow-y: auto;
  padding-right: 4px;
}
.split-desc {
  margin-bottom: 4px;
}
.process-names {
  color: #666;
  font-size: 12px;
}
.split-section {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed #e8e8e8;
}
.split-section-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  font-size: 13px;
  font-weight: 600;
  color: #333;
  margin-bottom: 8px;
}
.field-label {
  font-size: 12px;
  color: #666;
  margin-bottom: 6px;
}
.field-label-inline {
  font-size: 13px;
  color: #666;
  min-width: 64px;
}
.split-body {
  margin-top: 6px;
}
.field-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.hint,
.hint-inline {
  font-size: 12px;
  color: #999;
}
.hint {
  margin-top: 4px;
}
.kingdee-layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 12px;
  min-height: 0;
}
.kingdee-left,
.kingdee-right {
  min-width: 0;
}
.route-card-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 280px;
  overflow-y: auto;
  padding: 1px;
}
.route-card {
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  padding: 8px 10px;
  cursor: pointer;
  background: #fafafa;
  transition: border-color 0.15s, background 0.15s;
}
.route-card:hover {
  border-color: #93c5fd;
  background: #f8fbff;
}
.route-card.active {
  border-color: #2080f0;
  background: #eff6ff;
}
.route-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.route-code {
  font-weight: 600;
  color: #1f2937;
  font-size: 12px;
}
.route-step-count {
  font-size: 11px;
  color: #6b7280;
  white-space: nowrap;
}
.route-flow {
  margin-top: 4px;
  font-size: 11px;
  color: #6b7280;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.route-detail-sub {
  margin-left: 6px;
  font-weight: 400;
  font-size: 12px;
  color: #6b7280;
}
.route-detail-empty {
  height: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed #e5e7eb;
  border-radius: 6px;
  color: #9ca3af;
  font-size: 12px;
  background: #fafafa;
}
.assemble-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}
.custom-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}
.sum-line {
  margin-top: 6px;
  font-size: 12px;
  color: #666;
  text-align: right;
}
.sum-line.error {
  color: #d03050;
}
@media (max-width: 1100px) {
  .kingdee-layout {
    grid-template-columns: 1fr;
  }
  .route-card-list {
    max-height: 140px;
  }
}
</style>
